<script setup lang="ts">
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { message, Modal } from 'ant-design-vue'
import { getAppVoById, deployApp, deleteApp, downloadAppCode } from '@/api/appController'
import { listAppChatHistory } from '@/api/chatHistoryController'
import { getDeployUrl, getStaticPreviewUrl, API_BASE_URL } from '@/config/env'
import { useLoginUserStore } from '@/stores/useLoginUserStore'
import { SendOutlined, RocketOutlined, UserOutlined, RobotOutlined, InfoCircleOutlined, EyeOutlined, SettingOutlined, DeleteOutlined, CheckCircleFilled, DownOutlined, DownloadOutlined, EditOutlined, PaperClipOutlined, ThunderboltOutlined, MessageOutlined } from '@ant-design/icons-vue'
import { marked } from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'
import { getCodeGenTypeName } from '@/constants/codeGenType'
import { VisualEditor, type SelectedElement, injectEditScript } from '@/utils/visualEditor'
import logoImg from '@/assets/logo.png'
import MarkdownRenderer from '@/components/MarkdownRenderer.vue'

const route = useRoute()
const router = useRouter()
const loginUserStore = useLoginUserStore()

/**
 * 安全地处理ID，始终保持为字符串类型
 */
const safeGetId = (id: string | number | undefined): string => {
  if (!id) return ''

  const idString = String(id)
  console.log(`ID处理: ${id} -> ${idString} (type: ${typeof id} -> string)`)

  return idString
}

/**
 * 检查用户权限
 */
const checkUserPermission = () => {
  // 检查是否可以编辑（是管理员或者是应用的创建者）
  const currentUserId = loginUserStore.loginUser.id
  const appUserId = app.value.userId
  const isAdmin = loginUserStore.loginUser.userRole === 'admin'
  
  canEdit.value = isAdmin || (currentUserId && appUserId && currentUserId === appUserId)
  
  console.log('权限检查:', {
    currentUserId,
    appUserId,
    isAdmin,
    canEdit: canEdit.value
  })
}

/**
 * 检查用户是否在聊天区域底部
 */
const isUserAtBottom = (): boolean => {
  if (!messagesContainer.value) return true
  
  const container = messagesContainer.value
  const threshold = 100 // 100px的容差，认为用户在"接近底部"
  const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight
  
  return distanceFromBottom <= threshold
}

// 🔧 滚动速度控制变量
let scrollAnimationFrame: number | null = null
let lastScrollTime = 0
const SCROLL_THROTTLE_MS = 200 // 200ms滚动节流，进一步减缓滚动速度
const CONTENT_UPDATE_THROTTLE_MS = 100 // 100ms内容更新节流，减少抖动

// 🔧 滚动处理节流
let scrollUpdateTimer: NodeJS.Timeout | null = null
const throttledScrollUpdate = (callback: () => void) => {
  if (scrollUpdateTimer) {
    clearTimeout(scrollUpdateTimer)
  }
  scrollUpdateTimer = setTimeout(callback, CONTENT_UPDATE_THROTTLE_MS)
}

/**
 * 🚀 智能滚动到聊天区域底部 - 增加速度控制，让用户能看清生成的内容
 * 只有当用户在底部时才自动滚动，避免干扰用户查看历史消息
 */
const scrollToBottom = async () => {
  await nextTick()
  
  if (!messagesContainer.value || !isUserAtBottom() || isUserScrolling.value) {
    return
  }
  
  const now = Date.now()
  const timeSinceLastScroll = now - lastScrollTime
  
  // 🔧 滚动节流：防止滚动太快，让用户能看清内容
  if (timeSinceLastScroll < SCROLL_THROTTLE_MS) {
    if (scrollAnimationFrame) {
      cancelAnimationFrame(scrollAnimationFrame)
    }
    
    scrollAnimationFrame = requestAnimationFrame(() => {
      setTimeout(() => {
        if (messagesContainer.value && isUserAtBottom() && !isUserScrolling.value) {
          const targetScrollTop = messagesContainer.value.scrollHeight
          const currentScrollTop = messagesContainer.value.scrollTop
          const diff = targetScrollTop - currentScrollTop
          
          // 🔧 智能滚动策略：根据差距大小选择不同的滚动方式
          if (diff > 300) {
            // 大差距时，使用平滑滚动
            messagesContainer.value.scrollTo({
              top: targetScrollTop,
              behavior: 'smooth'
            })
          } else if (diff > 50) {
            // 中等差距时，使用分步滚动，更加可控
            const step = Math.ceil(diff / 3)
            messagesContainer.value.scrollTop = currentScrollTop + step
          } else {
            // 小差距时，直接跳转
            messagesContainer.value.scrollTop = targetScrollTop
          }
          
          lastScrollHeight.value = messagesContainer.value.scrollHeight
          lastScrollTime = Date.now()
        }
      }, SCROLL_THROTTLE_MS - timeSinceLastScroll)
    })
  } else {
    // 立即滚动（使用相同的智能滚动策略）
    const targetScrollTop = messagesContainer.value.scrollHeight
    const currentScrollTop = messagesContainer.value.scrollTop
    const diff = targetScrollTop - currentScrollTop
    
    if (diff > 300) {
      // 大差距时，使用平滑滚动
      messagesContainer.value.scrollTo({
        top: targetScrollTop,
        behavior: 'smooth'
      })
    } else if (diff > 50) {
      // 中等差距时，使用分步滚动，更加可控
      const step = Math.ceil(diff / 3)
      messagesContainer.value.scrollTop = currentScrollTop + step
    } else {
      // 小差距时，直接跳转
      messagesContainer.value.scrollTop = targetScrollTop
    }
    
    lastScrollHeight.value = messagesContainer.value.scrollHeight
    lastScrollTime = now
  }
}

/**
 * 保持用户当前的滚动位置
 * 当AI输出新内容导致容器高度增加时，平滑调整滚动位置以保持用户看到的内容不变
 */
const maintainScrollPosition = async () => {
  await nextTick()
  if (messagesContainer.value && !isUserAtBottom() && !isUserScrolling.value) {
    const currentScrollHeight = messagesContainer.value.scrollHeight
    const heightDiff = currentScrollHeight - lastScrollHeight.value
    
    if (heightDiff > 0) {
      // 内容高度增加了，平滑调整滚动位置以保持用户看到的内容不变
      const targetScrollTop = messagesContainer.value.scrollTop + heightDiff
      
      // 🔧 使用平滑滚动减少抖动，但距离很小时直接跳转
      if (heightDiff > 50) {
        messagesContainer.value.scrollTo({
          top: targetScrollTop,
          behavior: 'smooth'
        })
      } else {
        // 小幅度调整直接设置，避免过度动画
        messagesContainer.value.scrollTop = targetScrollTop
      }
      
      console.log('🔧 保持滚动位置：高度增加', heightDiff, 'px，平滑调整滚动位置')
    }
    
    lastScrollHeight.value = currentScrollHeight
  }
}

/**
 * 强制滚动到底部（用于发送新消息等场景）
 */
const forceScrollToBottom = async () => {
  await nextTick()
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
  }
}

/**
 * 滚动事件监听器
 */
const handleScroll = () => {
  if (messagesContainer.value) {
    const isAtBottom = isUserAtBottom()
    showScrollToBottomButton.value = !isAtBottom
    
    // 标记用户正在主动滚动
    isUserScrolling.value = true
    
    // 清除之前的计时器
    if (userScrollTimer) {
      clearTimeout(userScrollTimer)
    }
    
    // 设置计时器，300ms后认为用户停止滚动（缩短时间，提高响应性）
    userScrollTimer = setTimeout(() => {
      isUserScrolling.value = false
      // 更新滚动高度记录
      if (messagesContainer.value) {
        lastScrollHeight.value = messagesContainer.value.scrollHeight
      }
    }, 300)
  }
}

/**
 * 用户点击回到底部按钮
 */
const handleScrollToBottom = () => {
  // 清除用户滚动状态
  isUserScrolling.value = false
  if (userScrollTimer) {
    clearTimeout(userScrollTimer)
    userScrollTimer = null
  }
  
  forceScrollToBottom()
  showScrollToBottomButton.value = false
  
  // 更新滚动高度记录
  nextTick(() => {
    if (messagesContainer.value) {
      lastScrollHeight.value = messagesContainer.value.scrollHeight
    }
  })
}

// 应用信息
const app = ref<API.AppVO>({})
const appLoading = ref(false)

// 消息列表
interface ChatMessage {
  id: string
  role: 'user' | 'ai'
  content: string
  timestamp: number
  isStreaming?: boolean
}

const messages = ref<ChatMessage[]>([])
const messageInput = ref('')
const sendLoading = ref(false)
const messagesContainer = ref<HTMLElement>()

// 对话历史相关
const historyLoading = ref(false)
const hasMoreHistory = ref(false) // 默认为false，只有确实有更多历史时才设置为true
const lastCreateTime = ref<string>()
const historyLoaded = ref(false)

// 面板宽度调节
const chatWidth = ref(40) // 对话区域宽度百分比，默认40%
const previewWidth = ref(60) // 预览区域宽度百分比，默认60%
const isResizing = ref(false)
const startX = ref(0)
const startChatWidth = ref(0)

// 网站预览
const showPreview = ref(false)
const previewUrl = ref('')
const deployLoading = ref(false)

// 下载相关
const downloadLoading = ref(false)

// 权限控制
const canEdit = ref(true) // 是否可以编辑

// 左侧面板相关

// 部署成功弹窗相关
const deploySuccessVisible = ref(false) // 部署成功弹窗显示
const deployedUrl = ref('') // 部署后的访问地址

// 可视化编辑相关
const isEditMode = ref(false) // 是否在编辑模式
const selectedElement = ref<SelectedElement | null>(null) // 选中的元素
let visualEditor: VisualEditor | null = null // 可视化编辑器实例

// 滚动相关状态
const showScrollToBottomButton = ref(false) // 是否显示回到底部按钮
const lastScrollHeight = ref(0) // 记录上次的滚动高度
const isUserScrolling = ref(false) // 用户是否正在主动滚动
let userScrollTimer: NodeJS.Timeout | null = null // 用户滚动计时器

// SSE连接
let eventSource: EventSource | null = null

// 🔧 性能优化：长内容处理
let contentBuffer = ''
let lastRenderTime = 0
const RENDER_THROTTLE_MS = 20 // 减少到20ms渲染节流，提升实时性
const MAX_CONTENT_LENGTH = 50000 // 最大内容长度阈值
let contentUpdateTimer: NodeJS.Timeout | null = null

/**
 * 加载对话历史
 */
const loadChatHistory = async (loadMore = false) => {
  const appId = route.params.id as string
  console.log('=== 开始加载对话历史 ===')
  console.log('appId:', appId)
  console.log('loadMore:', loadMore)

  if (!appId) {
    console.error('appId不存在，无法加载对话历史')
    historyLoaded.value = true // 设置为已加载，避免显示加载状态
    return
  }

  // 如果是加载更多，但没有更多历史，直接返回
  if (loadMore && !hasMoreHistory.value) {
    console.log('没有更多历史，跳过加载')
    return
  }

  // 对于新应用，检查应用的创建时间，如果是刚创建的（比如5分钟内），可能没有历史
  // 但我们还是要尝试加载，因为可能有初始prompt生成的对话
  historyLoading.value = true

  try {
    const appIdString = safeGetId(appId)
    console.log('处理后的appIdString:', appIdString)

    if (!appIdString) {
      console.error('appId转换失败:', appId)
      return
    }

    const params: API.listAppChatHistoryParams = {
      appId: appIdString,
      pageSize: 10
    }

    // 如果是加载更多，传入最后一条消息的创建时间
    if (loadMore && lastCreateTime.value) {
      params.lastCreateTime = lastCreateTime.value
    }

    console.log('请求参数:', params)
    console.log('发送对话历史请求...')

    const res = await listAppChatHistory(params)
    console.log('对话历史API响应:', res)

    if (res.data.code === 0) {
      const historyMessages = res.data.data?.records || []
      console.log('获取到历史消息:', historyMessages.length, '条')
      console.log('历史消息详情:', historyMessages)

      // 如果没有历史消息，直接设置为已加载
      if (historyMessages.length === 0) {
        console.log('没有历史消息，跳过处理')
        if (!loadMore) {
          historyLoaded.value = true
          hasMoreHistory.value = false // 没有历史消息，肯定没有更多
        }
        return
      }

      // 转换历史消息为前端消息格式，并按时间升序排序
      const formattedMessages: ChatMessage[] = historyMessages
        .sort((a, b) => new Date(a.createTime || '').getTime() - new Date(b.createTime || '').getTime())
        .map((record, index) => ({
          id: `history_${record.id}_${index}`, // 使用后端ID + 索引生成唯一ID
          role: record.messageType === 'user' ? 'user' : 'ai',
          content: record.message || '',
          timestamp: new Date(record.createTime || '').getTime(),
          isStreaming: false // 历史消息都是已完成的，不应该显示流式状态
        }))

      console.log('转换后的消息:', formattedMessages)

      if (loadMore) {
        // 加载更多时，将新消息插入到列表开头
        messages.value = [...formattedMessages, ...messages.value]
      } else {
        // 🔧 关键修复：首次加载时，保护正在进行的对话
        const currentStreamingMessages = messages.value.filter(msg => 
          msg.role === 'ai' && msg.isStreaming
        )
        
        if (currentStreamingMessages.length > 0) {
          console.log('检测到正在进行的对话，合并历史消息和当前消息')
          console.log('历史消息数量:', formattedMessages.length)
          console.log('当前流式消息数量:', currentStreamingMessages.length)
          console.log('当前消息列表:', messages.value.map(m => ({ role: m.role, id: m.id, contentPreview: m.content?.slice(0, 20) })))
          
          // 🔧 关键修复：智能去重合并
          const currentNonHistoryMessages = messages.value.filter(msg => 
            !msg.id.startsWith('history_') // 排除历史消息
          )
          
          console.log('当前非历史消息:', currentNonHistoryMessages.map(m => ({ role: m.role, id: m.id, isStreaming: m.isStreaming, content: m.content?.slice(0, 30) })))
          
          // 检查是否有重复的用户消息内容
          const historyUserMessages = formattedMessages.filter(m => m.role === 'user')
          const currentUserMessages = currentNonHistoryMessages.filter(m => m.role === 'user')
          
          console.log('历史用户消息:', historyUserMessages.map(m => ({ content: m.content?.slice(0, 30) })))
          console.log('当前用户消息:', currentUserMessages.map(m => ({ content: m.content?.slice(0, 30) })))
          
          // 过滤掉与历史消息重复的当前用户消息
          const uniqueCurrentMessages = currentNonHistoryMessages.filter(currentMsg => {
            if (currentMsg.role !== 'user') return true // 保留所有非用户消息（如流式AI消息）
            
            // 检查是否与历史消息重复
            const isDuplicate = historyUserMessages.some(historyMsg => 
              historyMsg.content && currentMsg.content && 
              historyMsg.content.trim() === currentMsg.content.trim()
            )
            
            if (isDuplicate) {
              console.log('发现重复的用户消息，已过滤:', currentMsg.content?.slice(0, 30))
            }
            
            return !isDuplicate
          })
          
          console.log('去重后的当前消息:', uniqueCurrentMessages.map(m => ({ role: m.role, id: m.id, isStreaming: m.isStreaming })))
          
          // 将历史消息与去重后的当前消息合并
          messages.value = [...formattedMessages, ...uniqueCurrentMessages]
        } else {
          console.log('无正在进行的对话，直接设置历史消息')
          // 首次加载时，直接设置消息列表
          messages.value = formattedMessages
        }
      }

      // 更新分页信息
      if (historyMessages.length < 10) {
        // 如果返回的消息少于10条，说明没有更多历史了
        hasMoreHistory.value = false
      } else {
        // 如果返回了10条消息，可能还有更多
        hasMoreHistory.value = true
        // 更新最后一条消息的创建时间，用于下次分页
        const lastMessage = historyMessages[historyMessages.length - 1]
        lastCreateTime.value = lastMessage.createTime
      }

      if (!loadMore) {
        historyLoaded.value = true
      }

      console.log('对话历史加载成功:', formattedMessages.length, '条消息')

      // 如果是首次加载，需要强制滚动到底部
      if (!loadMore) {
        await nextTick()
        forceScrollToBottom()
      }
    } else {
      console.error('加载对话历史失败:', res.data)
      console.error('失败原因:', res.data.message)
      console.error('响应码:', res.data.code)
      if (!loadMore) {
        historyLoaded.value = true
        hasMoreHistory.value = false // 加载失败时，设置为没有更多历史
      }
    }
  } catch (error) {
    console.error('加载对话历史异常:', error)
    console.error('异常详情:', JSON.stringify(error, null, 2))
    if (!loadMore) {
      historyLoaded.value = true
      hasMoreHistory.value = false // 异常时，设置为没有更多历史
    }
  } finally {
    historyLoading.value = false
    console.log('=== 对话历史加载结束 ===')
  }
}

/**
 * 获取应用信息
 * 增加重试机制，因为应用刚创建可能需要时间同步到数据库
 */
const fetchAppInfo = async (retryCount = 0) => {
  const appId = route.params.id as string
  console.log('获取应用信息:')
  console.log('- route.params.id:', route.params.id)
  console.log('- appId:', appId)
  console.log('- appId type:', typeof appId)
  console.log('- retryCount:', retryCount)

  if (!appId) {
    console.error('应用ID为空，无法获取应用信息')
    return
  }

  // 只在第一次请求时显示loading
  if (retryCount === 0) {
    appLoading.value = true
  }

  try {
    const appIdString = safeGetId(appId)

    if (!appIdString) {
      console.error('应用ID为空:', appId)
      message.error('应用ID不存在')
      appLoading.value = false
      return
    }

    const res = await getAppVoById({ id: appIdString })
    console.log('获取应用信息响应:', res)

    if (res.data.code === 0 && res.data.data) {
      app.value = res.data.data
      console.log('应用信息加载成功:', app.value)
      appLoading.value = false
      
      // 检查用户权限
      console.log('开始检查用户权限...')
      checkUserPermission()
      console.log('用户权限检查完成')

      // 加载对话历史
      console.log('即将开始加载对话历史...')
      await loadChatHistory()
      console.log('对话历史加载完成')

      // 根据对话历史决定是否自动发送初始消息
      console.log('检查是否自动发送初始消息:', {
        hasInitPrompt: !!app.value.initPrompt,
        initPrompt: app.value.initPrompt,
        messagesLength: messages.value.length,
        canEdit: canEdit.value,
        shouldSend: app.value.initPrompt && messages.value.length === 0 && canEdit.value
      })

      if (app.value.initPrompt && messages.value.length === 0 && canEdit.value) {
        console.log('自动发送初始消息:', app.value.initPrompt)
        await sendMessageToAI(app.value.initPrompt, true)
      } else {
        console.log('不满足自动发送条件，跳过初始消息发送')
      }

      // 如果有至少2条对话记录，展示网站
      // 检查是否显示网站预览 - 需要至少2条消息且AI消息已完成
      const completedAIMessages = messages.value.filter(m => m.role === 'ai' && !m.isStreaming)
      const shouldShowPreview = messages.value.length >= 2 && completedAIMessages.length > 0
      
      console.log('检查是否显示网站预览:', {
        messagesLength: messages.value.length,
        completedAIMessages: completedAIMessages.length,
        streamingAIMessages: messages.value.filter(m => m.role === 'ai' && m.isStreaming).length,
        shouldShowPreview
      })
      
      if (shouldShowPreview) {
        console.log('满足条件，显示网站预览')
        showWebsitePreview()
      } else {
        console.log('不满足预览条件：需要至少2条消息且AI消息已完成生成')
      }
      return
    } else {
      // 如果是数据不存在且重试次数少于5次，则等待后重试
      if (res.data.message?.includes('请求数据不存在') && retryCount < 5) {
        console.log(`应用数据暂未同步，正在重试... (${retryCount + 1}/5)`)
        // 对于新应用，在重试期间设置合理的初始状态
        if (retryCount === 0) {
          // 只在第一次重试时设置，避免重复设置
          historyLoaded.value = true
          hasMoreHistory.value = false
        }
        setTimeout(() => {
          fetchAppInfo(retryCount + 1)
        }, 2000) // 固定2秒延迟
        return
      }
      
      appLoading.value = false
      message.error('应用不存在或已被删除')
      router.push('/')
    }
  } catch (error) {
    // 网络错误也进行重试
    if (retryCount < 5) {
      console.log(`网络请求失败，正在重试... (${retryCount + 1}/5)`)
      setTimeout(() => {
        fetchAppInfo(retryCount + 1)
      }, 2000)
      return
    }
    
    appLoading.value = false
    message.error('网络连接失败，请检查网络')
    router.push('/')
  }
}

/**
 * 静默获取应用信息，不会因为失败而跳转页面
 */
const fetchAppInfoSilently = async (retryCount = 0) => {
  const appId = route.params.id as string
  if (!appId) return

  try {
    const appIdString = safeGetId(appId)

    if (!appIdString) {
      console.error('静默获取: 应用ID为空:', appId)
      return
    }

    const res = await getAppVoById({ id: appIdString })
    if (res.data.code === 0 && res.data.data) {
      app.value = res.data.data
      console.log('应用信息获取成功:', app.value.appName)
      return
    } else {
      // 静默重试，最多10次
      if (retryCount < 10) {
        console.log(`静默重试获取应用信息... (${retryCount + 1}/10)`)
        setTimeout(() => {
          fetchAppInfoSilently(retryCount + 1)
        }, 3000)
        return
      }
      
      console.log('静默获取应用信息最终失败，但保持对话继续')
    }
  } catch (error) {
    // 静默重试
    if (retryCount < 10) {
      setTimeout(() => {
        fetchAppInfoSilently(retryCount + 1)
      }, 3000)
      return
    }
    
    console.log('静默获取应用信息网络错误，但保持对话继续')
  }
}

/**
 * 发送消息给AI
 * @param content 消息内容
 * @param isInitial 是否为初始消息
 */
const sendMessageToAI = async (content: string, isInitial = false) => {
  if (!content.trim()) return

  const appId = route.params.id as string
  if (!appId) return

  // 添加用户消息到聊天记录
    const userMessage: ChatMessage = {
    id: `user_${Date.now()}`,
    role: 'user',
      content: content,
      timestamp: Date.now()
    }
    messages.value.push(userMessage)
  console.log('添加用户消息:', { isInitial, content: content.slice(0, 50) + '...' })

  // 检测是否为Vue项目生成
  const isVueProject = content.toLowerCase().includes('vue') || 
                      content.toLowerCase().includes('管理系统') ||
                      content.toLowerCase().includes('管理平台') ||
                      content.toLowerCase().includes('博客平台')

  // 添加AI消息占位符
  const aiMessage: ChatMessage = {
    id: `ai_${Date.now()}`,
    role: 'ai',
    content: isVueProject ? '🚀 正在创建Vue项目，文件较多请耐心等待...\n\n' : '',
    timestamp: Date.now(),
    isStreaming: true
  }
  messages.value.push(aiMessage)
  
  // 如果是Vue项目，显示额外提示和定时更新
  if (isVueProject) {
    console.log('🎯 检测到Vue项目生成请求，已添加等待提示')
    
    // 30秒后提供进度更新
    setTimeout(() => {
      if (aiMessage.isStreaming && aiMessage.content.includes('正在创建Vue项目')) {
        aiMessage.content += '\n\n⏱️ Vue项目构建中，文件结构较复杂，继续等待...'
        console.log('🕐 Vue项目30秒进度提示已添加')
      }
    }, 30000)
    
    // 60秒后提供额外说明
    setTimeout(() => {
      if (aiMessage.isStreaming && aiMessage.content.includes('正在创建Vue项目')) {
        aiMessage.content += '\n\n🔄 正在优化代码结构和配置文件，即将完成...'
        console.log('🕐 Vue项目60秒进度提示已添加')
      }
    }, 60000)
  }

  console.log('✅ 创建AI消息占位符:', {
    id: aiMessage.id,
    role: aiMessage.role,
    isStreaming: aiMessage.isStreaming,
    messagesLength: messages.value.length
  })

  // 发送新消息时强制滚动到底部
  forceScrollToBottom()

  try {
    // 创建SSE连接
    const url = `${API_BASE_URL}/app/chat/gen/code?appId=${appId}&message=${encodeURIComponent(content)}`
    
    eventSource = new EventSource(url, {
      withCredentials: true
    })

    eventSource.onopen = () => {
      console.log('SSE连接已建立')
    }

    // 监听普通消息事件（数据传输）
    eventSource.onmessage = (event) => {
      try {
        const data = event.data
        console.log('收到SSE数据:', data)

        // 解析JSON格式的SSE数据
        if (data && data !== '') {
          try {
            const parsedData = JSON.parse(data)
            if (parsedData.d) {
              // 🔧 关键修复：查找正在流式传输的AI消息，而不是只检查最后一条
              const streamingAIMessage = messages.value
                .slice()
                .reverse()
                .find(msg => msg.role === 'ai' && msg.isStreaming)
              
              console.log('查找流式AI消息以追加数据:', {
                totalMessages: messages.value.length,
                hasStreamingAI: !!streamingAIMessage,
                streamingAIId: streamingAIMessage?.id,
                dataToAppend: parsedData.d,
                allAIMessages: messages.value.filter(m => m.role === 'ai').map(m => ({
                  id: m.id,
                  isStreaming: m.isStreaming,
                  contentLength: m.content?.length || 0
                }))
              })
              
              if (streamingAIMessage) {
                // 确保content是字符串
                if (typeof streamingAIMessage.content !== 'string') {
                  streamingAIMessage.content = ''
                }
                
                // 🔧 性能优化：使用节流更新，避免长内容时卡顿
                updateMessageContentThrottled(streamingAIMessage, parsedData.d)
                
                console.log('✅ SSE数据实时追加:', parsedData.d)
                console.log('当前消息长度:', streamingAIMessage.content.length)
                
                // 🔧 优化：使用节流机制减少频繁的滚动更新，提升体验
                throttledScrollUpdate(() => {
                  nextTick(() => {
                    // 智能滚动处理 - 只有用户在底部且没有主动滚动时才自动滚动
                    if (isUserAtBottom() && !isUserScrolling.value) {
                      scrollToBottom()
                    } else if (!isUserScrolling.value) {
                      maintainScrollPosition()
                    }
                    // 如果用户正在主动滚动，则不做任何自动滚动操作
                    
                    // 🔧 节流代码高亮：只在特定条件下应用，减少频繁调用
                    throttledCodeHighlight()
                  })
                })
              } else {
                console.warn('❌ 无法追加SSE数据，没有找到流式AI消息!', {
                  totalMessages: messages.value.length,
                  aiMessagesCount: messages.value.filter(m => m.role === 'ai').length,
                  streamingAICount: messages.value.filter(m => m.role === 'ai' && m.isStreaming).length,
                  dataToAppend: parsedData.d
                })
                
                // 🔧 安全措施：如果没有流式AI消息但收到了SSE数据，关闭连接
                console.warn('关闭无效的SSE连接...')
                if (eventSource) {
                  eventSource.close()
                  eventSource = null
                }
                sendLoading.value = false
              }
            }
          } catch (parseError) {
            // 如果不是JSON格式，直接使用原始数据
            const streamingAIMessage = messages.value
              .slice()
              .reverse()
              .find(msg => msg.role === 'ai' && msg.isStreaming)
              
            if (streamingAIMessage) {
              // 确保content是字符串
              if (typeof streamingAIMessage.content !== 'string') {
                streamingAIMessage.content = ''
              }
              
              // 🔧 性能优化：使用节流更新，避免长内容时卡顿
              updateMessageContentThrottled(streamingAIMessage, data)
              
              console.log('✅ 原始SSE数据实时追加:', data)
              console.log('当前消息长度:', streamingAIMessage.content.length)
              
              // 🔧 优化：使用节流机制减少频繁的滚动更新，提升体验
              throttledScrollUpdate(() => {
                nextTick(() => {
                  // 智能滚动处理 - 只有用户在底部且没有主动滚动时才自动滚动
                  if (isUserAtBottom() && !isUserScrolling.value) {
                    scrollToBottom()
                  } else if (!isUserScrolling.value) {
                    maintainScrollPosition()
                  }
                  // 如果用户正在主动滚动，则不做任何自动滚动操作
                  
                  // 🔧 节流代码高亮：只在特定条件下应用，减少频繁调用
                  throttledCodeHighlight()
                })
              })
            } else {
              console.warn('❌ 原始数据无法追加，没有找到流式AI消息!')
              // 关闭无效连接
              if (eventSource) {
                eventSource.close()
                eventSource = null
              }
              sendLoading.value = false
            }
          }
        }
      } catch (error) {
        console.error('解析SSE数据失败:', error)
      }
    }

    // 监听 done 事件（完成事件）
    eventSource.addEventListener('done', (event) => {
      console.log('=== 收到 done 事件，SSE传输完成 ===')
      
      // 调试：显示当前所有消息的详细信息
      console.log('当前消息列表详情:', messages.value.map(m => ({ 
        role: m.role, 
        id: m.id, 
        isStreaming: m.isStreaming,
        contentLength: m.content?.length || 0,
        contentPreview: m.content?.slice(0, 50) || ''
      })))
      
      // 流式传输完成 - 查找正在流式传输的AI消息
      const streamingAIMessage = messages.value
        .slice()
        .reverse()
        .find(msg => msg.role === 'ai' && msg.isStreaming)
      
      console.log('查找流式AI消息结果:', streamingAIMessage ? {
        id: streamingAIMessage.id,
        role: streamingAIMessage.role,
        isStreaming: streamingAIMessage.isStreaming,
        contentLength: streamingAIMessage.content?.length || 0
      } : '未找到流式AI消息')
      
      if (streamingAIMessage) {
        streamingAIMessage.isStreaming = false
        console.log('✅ 流式AI消息标记为完成:', streamingAIMessage.content.slice(0, 100) + '...')
        console.log('消息完整内容长度:', streamingAIMessage.content.length)
        console.log('消息isStreaming状态:', streamingAIMessage.isStreaming)
      } else {
        console.warn('❌ 无法找到正在流式传输的AI消息')
      const lastMessage = messages.value[messages.value.length - 1]
        if (lastMessage) {
          console.warn('最后一条消息详情:', {
            isAI: lastMessage.role === 'ai',
            isStreaming: lastMessage.isStreaming,
            role: lastMessage.role,
            id: lastMessage.id
          })
        }
        console.warn('所有AI消息状态:', messages.value
          .filter(m => m.role === 'ai')
          .map(m => ({
            id: m.id,
            isStreaming: m.isStreaming,
            contentLength: m.content?.length || 0
          }))
        )
      }
      
      eventSource?.close()
      eventSource = null
      sendLoading.value = false

      console.log('当前应用信息:', {
        id: app.value.id,
        codeGenType: app.value.codeGenType,
        appName: app.value.appName
      })
      console.log('路由参数ID:', route.params.id)

      // 如果有至少2条对话记录，延迟显示预览，确保后端文件已生成
      if (messages.value.length >= 2) {
        console.log('SSE完成，准备显示预览...')
        
        // 🔧 关键修复：立即尝试一次，如果已经有预览则强制刷新
        const isRefresh = showPreview.value // 如果已经显示预览，则是刷新操作
        showWebsitePreview(isRefresh)
        
        // 延迟多次尝试，确保预览能正确显示
        const retryDelays = [1000, 3000, 5000] // 1秒、3秒、5秒后重试
        retryDelays.forEach((delay, index) => {
          setTimeout(() => {
            console.log(`延迟${delay}ms后重试显示预览 (第${index + 1}次重试)...`)
            showWebsitePreview(true) // 重试时总是强制刷新
          }, delay)
        })
      }
    })

    // 🔧 增强的业务错误处理
    eventSource.addEventListener('business-error', (event: MessageEvent) => {
      console.error('🚨 收到业务错误事件:', event.data)
      
      try {
        const errorData = JSON.parse(event.data)
        console.error('📋 SSE业务错误详情:', errorData)

        // 查找正在流式传输的AI消息
        const streamingAIMessage = messages.value
          .slice()
          .reverse()
          .find(msg => msg.role === 'ai' && msg.isStreaming)

        if (streamingAIMessage) {
          streamingAIMessage.isStreaming = false
          
          // 根据错误类型显示不同的错误信息
          const errorType = errorData.type || 'unknown'
          const errorMessage = errorData.message || '生成过程中出现错误'
          
          let displayMessage = ''
          switch (errorType) {
            case 'rate_limit':
              displayMessage = `⏳ ${errorMessage}\n\n请稍后重试，或考虑升级账户以获得更高的使用限额。`
              break
            case 'api_quota_exceeded':
              displayMessage = `💳 ${errorMessage}\n\n今日API调用次数已用完，请明天再试或联系管理员。`
              break
            case 'content_filter':
              displayMessage = `🛡️ ${errorMessage}\n\n请修改您的输入内容，确保符合使用规范。`
              break
            case 'model_overload':
              displayMessage = `🔄 ${errorMessage}\n\n AI服务暂时繁忙，请稍后重试。`
              break
            case 'timeout':
              displayMessage = `⏰ ${errorMessage}\n\n生成时间过长，已自动停止。请尝试简化需求或重新提交。`
              break
            case 'invalid_request':
              displayMessage = `❓ ${errorMessage}\n\n请检查您的输入是否正确，或重新描述需求。`
              break
            default:
              displayMessage = `❌ ${errorMessage}\n\n如果问题持续出现，请联系技术支持。`
          }
          
          streamingAIMessage.content = displayMessage
          console.log('✅ 业务错误消息已设置:', displayMessage)
          
          // 在错误消息后添加重试提示
          streamingAIMessage.content += '\n\n---\n\n💡 **遇到问题？**\n- 等待片刻后重新发送消息\n- 尝试简化或重新描述需求\n- 如果问题持续，请联系技术支持'
          
          // 显示用户友好的错误提示
          const userFriendlyMessage = errorData.userMessage || errorMessage
          message.error(userFriendlyMessage, 5) // 显示5秒
          
        } else {
          console.warn('❌ 收到业务错误但未找到流式AI消息')
          // 如果没有找到流式消息，创建一个错误消息
          const errorMessage = errorData.message || '服务暂时不可用'
          message.error(errorMessage)
        }

      } catch (parseError) {
        console.error('❌ 解析业务错误事件失败:', parseError, '原始数据:', event.data)
        
        // 解析失败时的备用处理
        const streamingAIMessage = messages.value
          .slice()
          .reverse()
          .find(msg => msg.role === 'ai' && msg.isStreaming)
          
        if (streamingAIMessage) {
          streamingAIMessage.isStreaming = false
          streamingAIMessage.content = '❌ 服务器返回了无法识别的错误信息\n\n请重试，如果问题持续请联系技术支持。'
        }
        
        message.error('服务器错误，请重试')
      }

      // 清理SSE连接
      eventSource?.close()
      eventSource = null
      sendLoading.value = false
    })

    // 🔧 增强的网络错误处理
    eventSource.addEventListener('network-error', (event: MessageEvent) => {
      console.error('🌐 收到网络错误事件:', event.data)
      
      const streamingAIMessage = messages.value
        .slice()
        .reverse()
        .find(msg => msg.role === 'ai' && msg.isStreaming)

      if (streamingAIMessage) {
        streamingAIMessage.isStreaming = false
        streamingAIMessage.content = '🌐 网络连接出现问题\n\n请检查网络连接后重试。'
      }

      message.error('网络连接异常，请检查网络后重试')
      
      eventSource?.close()
      eventSource = null
      sendLoading.value = false
    })

    // 🔧 原有的连接错误处理（保持向后兼容）
    eventSource.onerror = (error) => {
      console.error('💥 SSE连接错误:', error)
      
      const streamingAIMessage = messages.value
        .slice()
        .reverse()
        .find(msg => msg.role === 'ai' && msg.isStreaming)
        
      if (streamingAIMessage) {
        streamingAIMessage.isStreaming = false
        
        // 如果消息内容为空，说明连接在开始传输前就失败了
        if (streamingAIMessage.content === '' || !streamingAIMessage.content) {
          streamingAIMessage.content = '🔌 连接中断\n\n生成过程中连接意外断开，请重试。如果问题持续出现，请稍后再试。'
        } else {
          // 如果已有部分内容，在末尾添加中断提示
          streamingAIMessage.content += '\n\n⚠️ *生成过程中连接中断，上述内容可能不完整*'
        }
      }
      
      eventSource?.close()
      eventSource = null
      sendLoading.value = false
      
      // 显示错误提示
      message.error('连接中断，请重试', 3)
      
      // SSE断开时，如果有至少2条对话记录，强制显示预览（兼容原有逻辑）
      if (messages.value.length >= 2) {
        console.log('📺 SSE断开，尝试显示预览...')
      setTimeout(() => {
        showWebsitePreview()
      }, 1000)
      }
    }

  } catch (error) {
    console.error('发送消息失败:', error)
    const lastMessage = messages.value[messages.value.length - 1]
    if (lastMessage && lastMessage.role === 'ai' && lastMessage.isStreaming) {
      lastMessage.isStreaming = false
      lastMessage.content = '发送消息失败，请检查网络连接'
    }
    sendLoading.value = false
  }
}

/**
 * 发送用户消息
 */
const handleSendMessage = async () => {
  if (!messageInput.value.trim() || sendLoading.value) return

  const content = messageInput.value.trim()
  
  // 🔧 强化输入框清空逻辑
  messageInput.value = ''
  await nextTick() // 确保DOM更新
  console.log('输入框已清空，当前值:', messageInput.value)
  
  sendLoading.value = true

  try {
    await sendMessageToAI(content)
  } catch (error) {
    console.error('发送消息失败:', error)
    sendLoading.value = false
  }
  // 注意：不在这里设置 sendLoading.value = false，而是在SSE完成或错误时设置
}

/**
 * 显示网站预览
 */
const showWebsitePreview = (forceRefresh = false) => {
  console.log('=== 显示网站预览函数被调用 ===')
  console.log('强制刷新:', forceRefresh)
  console.log('完整应用信息:', JSON.stringify(app.value, null, 2))
  console.log('应用ID:', app.value.id)
  console.log('代码生成类型:', app.value.codeGenType)
  console.log('路由参数ID:', route.params.id)
  
  // 优先使用应用信息中的ID，如果没有则使用路由参数
  const appId = app.value.id || route.params.id
  
  if (!appId) {
    console.log('应用ID不存在，无法显示预览')
    message.warning('应用ID不存在，无法显示预览')
    return
  }
  
  // 如果没有codeGenType，使用默认值"multi_file"
  const codeGenType = app.value.codeGenType || 'multi_file'
  
  // 生成预览URL - 如果强制刷新，添加时间戳避免缓存
  let generatedUrl = getStaticPreviewUrl(codeGenType, appId)
  if (forceRefresh) {
    const timestamp = Date.now()
    generatedUrl += (generatedUrl.includes('?') ? '&' : '?') + `_t=${timestamp}`
    console.log('添加时间戳强制刷新:', timestamp)
  }
  
  previewUrl.value = generatedUrl
  showPreview.value = true
  
  console.log('最终预览URL:', previewUrl.value)
  console.log('预览状态设置为:', showPreview.value)
  console.log('URL生成参数:', { codeGenType, appId })
  console.log('getStaticPreviewUrl函数返回:', generatedUrl)
  
  // 添加延迟验证，确保状态正确设置
  nextTick(() => {
    console.log('nextTick后预览状态:', {
      showPreview: showPreview.value,
      previewUrl: previewUrl.value,
      DOMElement: document.querySelector('.website-preview') ? '存在' : '不存在'
    })
  })
  
  console.log('=== 预览URL生成完成 ===')
}

/**
 * 预览页面加载完成处理
 */
const onPreviewLoad = (event: any) => {
  console.log('预览页面加载完成:', previewUrl.value)
  
  try {
    const iframe = event.target as HTMLIFrameElement
    const iframeWindow = iframe.contentWindow
    
    if (iframeWindow && iframeWindow.location.origin === window.location.origin) {
      // 注入可视化编辑脚本
      setTimeout(() => {
        injectEditScript(iframeWindow)
        console.log('已注入可视化编辑脚本')
        
        // 初始化可视化编辑器
        initVisualEditor()
      }, 500) // 延迟一下确保iframe完全加载
    } else {
      console.warn('iframe域名不同，无法注入编辑脚本')
    }
  } catch (error) {
    console.error('处理iframe加载事件失败:', error)
  }
}

const onPreviewError = (event: any) => {
  console.log('预览页面加载失败，URL:', previewUrl.value)
  console.log('错误事件:', event)
  message.warning('预览页面暂时无法加载，请检查后端服务或稍后重试')
  
  // 可以尝试重新生成预览
  setTimeout(() => {
    console.log('5秒后自动重试预览...')
    showWebsitePreview()
  }, 5000)
}


/**
 * 跳转到应用详情页面
 */
const goToAppDetail = () => {
  const currentAppId = app.value.id || route.params.id
  console.log('点击了应用详情按钮, app.value.id:', app.value.id, 'route.params.id:', route.params.id, 'currentAppId:', currentAppId)

  if (!currentAppId) {
    message.warning('应用ID不存在，无法查看详情')
    return
  }

  try {
    const detailUrl = `/app/detail/${currentAppId}`
    console.log('跳转到:', detailUrl)
    const routeData = router.resolve(detailUrl)
    window.open(routeData.href, '_blank')
  } catch (error) {
    console.error('跳转失败:', error)
    message.error('跳转失败，请稍后再试')
  }
}

/**
 * 下载应用代码
 */
const handleDownload = async () => {
  const appId = route.params.id as string
  if (!appId) {
    message.error('应用ID不存在')
    return
  }

  const appIdString = safeGetId(appId)
  if (!appIdString) {
    message.error('应用ID格式错误')
    return
  }

  console.log('开始下载应用代码:', {
    appId: appIdString,
    appName: app.value.appName
  })

  downloadLoading.value = true

  try {
    // 🔧 关键：调用下载接口，配置responseType为blob处理ZIP文件
    const response = await downloadAppCode({ 
      appId: appIdString 
    } as any, {
      responseType: 'blob',  // 重要：指定响应类型为blob
      timeout: 30000,       // 30秒超时，ZIP文件可能较大
    })
    
    console.log('下载响应:', response)

    // 处理ZIP文件下载
    if (response && response.data) {
      // response.data 已经是Blob对象
      const blob = response.data
      
      // 创建下载链接
      const url = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = url
      
      // 设置下载文件名 - 清理文件名中的特殊字符
      const cleanAppName = (app.value.appName || 'app').replace(/[^\w\u4e00-\u9fa5]/g, '_')
      const fileName = `${cleanAppName}_source_code.zip`
      link.download = fileName
      
      // 触发下载
      document.body.appendChild(link)
      link.click()
      
      // 清理
      document.body.removeChild(link)
      window.URL.revokeObjectURL(url)
      
      message.success(`代码下载成功！文件名：${fileName}`)
      console.log('下载完成:', fileName)
    } else {
      message.error('下载失败：响应数据为空')
    }
  } catch (error) {
    console.error('下载应用代码失败:', error)
    message.error('下载失败，请检查网络连接或稍后重试')
  } finally {
    downloadLoading.value = false
  }
}

/**
 * 格式化日期
 */
const formatDate = (dateString?: string) => {
  if (!dateString) return '未知'
  const date = new Date(dateString)
  return date.toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit'
  })
}

/**
 * 获取生成类型对应的标签颜色
 */
const getTypeColor = (codeGenType: string) => {
  const colorMap: { [key: string]: string } = {
    'html': 'orange',
    'multi_file': 'blue',
    'vue_project': 'green'
  }
  return colorMap[codeGenType] || 'default'
}

/**
 * 初始化可视化编辑器
 */
const initVisualEditor = () => {
  if (visualEditor) {
    visualEditor.destroy()
  }

  visualEditor = new VisualEditor({
    iframeId: 'website-preview',
    onElementHover: (element) => {
      // 可以在这里处理悬浮效果，比如显示工具提示
      console.log('悬浮元素:', element)
    },
    onElementSelect: (element) => {
      selectedElement.value = element
      console.log('选中元素:', element)
    },
    onElementUnselect: () => {
      selectedElement.value = null
    }
  })
}

/**
 * 切换编辑模式
 */
const toggleEditMode = () => {
  if (!showPreview.value) {
    message.warning('请先生成网站预览')
    return
  }

  if (!visualEditor) {
    initVisualEditor()
  }

  if (isEditMode.value) {
    // 退出编辑模式
    visualEditor?.exitEditMode()
    isEditMode.value = false
    selectedElement.value = null
    
    // 确保iframe内的编辑样式被清除
    const iframe = document.getElementById('website-preview') as HTMLIFrameElement
    if (iframe && iframe.contentWindow) {
      try {
        // 向iframe发送强制清理消息
        iframe.contentWindow.postMessage({
          type: 'FORCE_CLEAR_STYLES'
        }, window.location.origin)
      } catch (error) {
        console.warn('发送清理样式消息失败:', error)
      }
    }
    
    console.log('退出编辑模式，清理完成')
  } else {
    // 进入编辑模式
    visualEditor?.enterEditMode()
    isEditMode.value = true
    console.log('进入编辑模式')
  }
}

/**
 * 移除选中的元素
 */
const removeSelectedElement = () => {
  selectedElement.value = null
  visualEditor?.clearSelectedElement()
}

/**
 * 获取输入框占位符文本
 */
const getInputPlaceholder = () => {
  if (selectedElement.value) {
    return `正在编辑 ${selectedElement.value.tagName.toLowerCase()} 元素，描述您想要的修改...`
  }
  return '请描述你想生成的网站，越详细效果越好哦'
}

/**
 * 格式化选中元素的描述
 */
const formatElementDescription = (element: SelectedElement): string => {
  const parts = []
  
  if (element.tagName) {
    parts.push(`标签: ${element.tagName.toLowerCase()}`)
  }
  
  if (element.id) {
    parts.push(`ID: ${element.id}`)
  }
  
  if (element.className) {
    parts.push(`类名: ${element.className}`)
  }
  
  if (element.textContent) {
    parts.push(`文本: ${element.textContent.substring(0, 50)}${element.textContent.length > 50 ? '...' : ''}`)
  }
  
  return parts.join(' | ')
}

/**
 * 查看作品
 */
const handleViewWork = () => {
  if (!app.value.deployKey) {
    message.error('该应用尚未部署')
    return
  }

  const deployUrl = getDeployUrl(app.value.deployKey)
  window.open(deployUrl, '_blank')
}

/**
 * 作品设置
 */
const handleSettings = () => {
  router.push(`/app/edit/${app.value.id}`)
}

/**
 * 删除作品
 */
const handleDeleteApp = () => {
  const currentAppId = app.value.id || route.params.id
  
  if (!currentAppId) {
    message.warning('应用ID不存在，无法删除')
    return
  }

  Modal.confirm({
    title: '确认删除',
    content: `确定要删除应用「${app.value.appName}」吗？此操作不可撤销。`,
    okText: '确认删除',
    okType: 'danger',
    cancelText: '取消',
    onOk: async () => {
      try {
        const appIdString = safeGetId(currentAppId)
        if (!appIdString) {
          message.error('应用ID格式错误')
          return
        }

        const res = await deleteApp({ id: appIdString })
        if (res.data.code === 0) {
          message.success('删除成功')
          // 删除成功后跳转到首页
          router.push('/')
        } else {
          message.error(res.data.message || '删除失败')
        }
      } catch (error) {
        console.error('删除应用失败:', error)
        message.error('删除失败，请检查网络连接')
      }
    }
  })
}

/**
 * 处理键盘按键事件
 */
const handleKeyPress = (event: KeyboardEvent) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault()
    sendMessageWithVisualEdit()
  }
}

/**
 * 发送消息 - 可视化编辑增强版
 */
const sendMessageWithVisualEdit = async () => {
  if (!messageInput.value.trim() || !canEdit.value || sendLoading.value) {
    return
  }

  const appId = route.params.id as string
  if (!appId) {
    message.error('应用ID不存在')
    return
  }

  // 构建发送的消息
  let messageToSend = messageInput.value.trim()
  
  // 如果有选中的元素，添加到提示词中
  if (selectedElement.value) {
    const elementInfo = `
请针对以下选中的元素进行修改：
- 标签: ${selectedElement.value.tagName.toLowerCase()}
- ID: ${selectedElement.value.id || '无'}
- 类名: ${selectedElement.value.className || '无'}
- 选择器: ${selectedElement.value.selector}
- 当前文本内容: ${selectedElement.value.textContent.substring(0, 100)}

用户需求: ${messageToSend}`
    
    messageToSend = elementInfo
    
    // 清除选中元素并退出编辑模式
    selectedElement.value = null
    if (isEditMode.value) {
      visualEditor?.exitEditMode()
      isEditMode.value = false
    }
  }

  console.log('🚀 可视化编辑模式发送消息:', messageToSend)

  // 清空输入框
  messageInput.value = ''
  await nextTick() // 确保DOM更新

  // 🔧 关键修复：直接使用已经修复好的 sendMessageToAI 函数，避免重复逻辑
  console.log('✅ 调用修复后的sendMessageToAI函数，确保真正实时流式传输')
  try {
    await sendMessageToAI(messageToSend)
  } catch (error) {
    console.error('发送消息失败:', error)
    sendLoading.value = false
  }
}

/**
 * 复制部署地址
 */
const copyDeployUrl = async () => {
  try {
    await navigator.clipboard.writeText(deployedUrl.value)
    message.success('部署地址已复制到剪贴板')
  } catch (error) {
    console.error('复制失败:', error)
    message.error('复制失败，请手动复制')
  }
}

/**
 * 访问部署的网站
 */
const visitDeployedSite = () => {
  window.open(deployedUrl.value, '_blank')
  deploySuccessVisible.value = false
}

/**
 * 开始拖拽调整面板大小
 */
const startResize = (e: MouseEvent) => {
  isResizing.value = true
  startX.value = e.clientX
  startChatWidth.value = chatWidth.value

  // 添加全局事件监听
  document.addEventListener('mousemove', handleResize, { passive: false })
  document.addEventListener('mouseup', stopResize)

  // 防止文本选择和其他干扰
  document.body.style.userSelect = 'none'
  document.body.style.cursor = 'col-resize'
  document.body.classList.add('resizing')
  e.preventDefault()
}

/**
 * 重置面板宽度到默认值
 */
const resetPanelWidth = () => {
  chatWidth.value = 50
  previewWidth.value = 50
}

/**
 * 处理拖拽过程
 */
const handleResize = (e: MouseEvent) => {
  if (!isResizing.value) return

  const container = document.querySelector('.chat-content') as HTMLElement
  if (!container) return

  const containerWidth = container.offsetWidth
  const deltaX = e.clientX - startX.value
  const deltaPercent = (deltaX / containerWidth) * 100

  let newChatWidth = startChatWidth.value + deltaPercent

  // 限制最小和最大宽度，增加更合理的范围
  newChatWidth = Math.max(30, Math.min(70, newChatWidth))

  chatWidth.value = newChatWidth
  previewWidth.value = 100 - newChatWidth

  e.preventDefault()
}

/**
 * 停止拖拽
 */
const stopResize = () => {
  isResizing.value = false

  // 移除全局事件监听
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)

  // 恢复默认样式
  document.body.style.userSelect = ''
  document.body.style.cursor = ''
  document.body.classList.remove('resizing')
}

/**
 * 部署应用
 */
const handleDeploy = async () => {
  const currentAppId = app.value.id || route.params.id
  console.log('点击了部署按钮, app.value.id:', app.value.id, 'route.params.id:', route.params.id, 'currentAppId:', currentAppId, 'deployLoading:', deployLoading.value)

  if (!currentAppId) {
    message.warning('应用ID不存在，无法部署')
    return
  }

  // 在部署之前，先验证应用是否存在
  console.log('部署前验证应用存在性...')
  try {
    const appIdString = safeGetId(currentAppId)

    if (!appIdString) {
      message.error('应用ID为空，无法部署')
      return
    }

    // 先检查应用是否存在
    const checkRes = await getAppVoById({ id: appIdString })
    console.log('部署前检查结果:', checkRes)

    if (checkRes.data.code !== 0 || !checkRes.data.data) {
      message.error('无法部署：应用不存在或已被删除')
      console.error('应用不存在:', checkRes)
      return
    }

    console.log('应用存在，继续部署流程...')
  } catch (error) {
    console.error('验证应用存在性失败:', error)
    message.error('无法验证应用状态，请稍后再试')
    return
  }

  deployLoading.value = true

  const appIdString = safeGetId(currentAppId)

  if (!appIdString) {
    console.error('应用ID为空:', currentAppId)
    message.error('应用ID不存在')
    deployLoading.value = false
    return
  }

  try {
    console.log('发送部署请求, 参数:', { appId: appIdString })
    const res = await deployApp({ appId: appIdString })
    console.log('部署响应:', res)

    if (res.data.code === 0 && res.data.data) {
      const deployUrl = res.data.data

      // 设置部署成功的信息并显示弹窗
      deployedUrl.value = deployUrl
      deploySuccessVisible.value = true

      // 重新获取应用信息以更新deployKey
      await fetchAppInfoSilently()

      console.log('部署成功，URL:', deployUrl)
    } else {
      const errorMsg = res.data.message || '未知错误'
      console.error('部署失败:', {
        code: res.data.code,
        message: errorMsg,
        appId: appIdString,
        fullResponse: res
      })

      if (errorMsg.includes('应用不存在')) {
        message.error('部署失败：应用不存在，请检查应用ID是否正确')
        // 尝试重新加载应用信息
        console.log('尝试重新加载应用信息...')
        fetchAppInfo()
      } else {
        message.error('部署失败：' + errorMsg)
      }
    }
  } catch (error) {
    console.error('部署失败:', error)
    message.error('部署失败，请检查网络连接')
  } finally {
    deployLoading.value = false
  }
}



// 页面加载时的初始化
onMounted(() => {
  const appId = route.params.id as string
  
  // 🔧 添加滚动监听器和初始化滚动状态
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.addEventListener('scroll', handleScroll)
      // 初始化滚动高度记录
      lastScrollHeight.value = messagesContainer.value.scrollHeight
    }
  })
  
  // 检查是否是新创建的应用（从URL参数或sessionStorage判断）
  const isNewApp = sessionStorage.getItem(`newApp_${appId}`)
  if (isNewApp) {
    // 清除标记
    sessionStorage.removeItem(`newApp_${appId}`)
    
    // 对于新创建的应用，先开始对话，再获取应用信息
    const initPrompt = sessionStorage.getItem(`initPrompt_${appId}`)
    if (initPrompt) {
      sessionStorage.removeItem(`initPrompt_${appId}`)
      // 直接发送初始提示词给AI
      sendMessageToAI(initPrompt, true)
    }
    
    // 延迟获取应用信息，但不要中断对话
    setTimeout(() => {
      fetchAppInfoSilently()
    }, 3000)
  } else {
    // 正常获取应用信息
    fetchAppInfo()
  }
})

// 页面卸载时清理资源
onUnmounted(() => {
    if (eventSource) {
      eventSource.close()
      eventSource = null
    }
  
  if (visualEditor) {
    visualEditor.destroy()
    visualEditor = null
  }
  
  // 🔧 移除滚动监听器和清理计时器
  if (messagesContainer.value) {
    messagesContainer.value.removeEventListener('scroll', handleScroll)
  }
  
  // 🔧 性能优化：清理所有定时器和资源
  if (userScrollTimer) {
    clearTimeout(userScrollTimer)
    userScrollTimer = null
  }
  
  if (scrollUpdateTimer) {
    clearTimeout(scrollUpdateTimer)
    scrollUpdateTimer = null
  }
  
  if (highlightTimer) {
    clearTimeout(highlightTimer)
    highlightTimer = null
  }
  
  if (contentUpdateTimer) {
    clearTimeout(contentUpdateTimer)
    contentUpdateTimer = null
  }
  
  if (scrollAnimationFrame) {
    cancelAnimationFrame(scrollAnimationFrame)
    scrollAnimationFrame = null
  }
  
  // 🔧 清理缓冲区
  contentBuffer = ''
  
  console.log('🧹 组件卸载，所有资源已清理')
})

/**
 * 配置marked选项
 */
const configureMarked = () => {
  marked.setOptions({
    highlight: function(code, lang) {
      if (lang && hljs.getLanguage(lang)) {
        try {
          return hljs.highlight(code, { language: lang }).value
        } catch (err) {
          console.warn('代码高亮失败:', err)
          return code
        }
      }
      try {
        return hljs.highlightAuto(code).value
      } catch (err) {
        console.warn('自动高亮失败:', err)
      return code
      }
    },
    renderer: createCustomRenderer(),
    breaks: true, // 支持换行
    gfm: true,    // 支持GitHub风格Markdown
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: false
  })
}

/**
 * 自定义渲染器，优化代码块显示
 */
const createCustomRenderer = () => {
  const renderer = new marked.Renderer()
  
  // 自定义代码块渲染
  renderer.code = function(code, language, escaped) {
    const lang = language || 'plaintext'
    const validLang = lang && hljs.getLanguage(lang) ? lang : 'plaintext'
    
    // 获取语言图标 - 支持Vue生态完整语言
    const getLanguageIcon = (lang: string) => {
      const icons: Record<string, string> = {
        // JavaScript/TypeScript 生态
        'javascript': '⚡',
        'js': '⚡',
        'jsx': '⚛️',
        'typescript': '🔷',
        'ts': '🔷',
        'tsx': '🔷',
        'vue': '💚',
        'json': '📋',
        
        // 样式语言
        'css': '🎨',
        'scss': '💜',
        'sass': '💜',
        'less': '🔵',
        'stylus': '🟢',
        
        // 标记语言
        'html': '🌐',
        'xml': '📄',
        'svg': '🖼️',
        'markdown': '📝',
        'md': '📝',
        
        // 配置语言
        'yaml': '⚙️',
        'yml': '⚙️',
        'toml': '⚙️',
        'ini': '⚙️',
        'env': '🔧',
        
        // 模板语言
        'pug': '🐶',
        'jade': '🐶',
        'handlebars': '🤝',
        'mustache': '👨‍🦲',
        
        // 其他前端相关
        'graphql': '💎',
        'sql': '🗄️',
        'bash': '⚫',
        'shell': '⚫',
        'dockerfile': '🐳',
        
        // 其他语言
        'python': '🐍',
        'java': '☕',
        'php': '🐘',
        'ruby': '💎',
        'go': '🐹',
        'rust': '🦀',
        'cpp': '⚙️',
        'c': '⚙️',
        'csharp': '🔷',
        'swift': '🦉',
        'kotlin': '🔶',
        
        // 默认
        'plaintext': '📝',
        'text': '📝'
      }
      return icons[lang] || '📝'
    }

    // 获取语言显示名称 - 支持Vue生态完整语言
    const getLanguageDisplayName = (lang: string) => {
      const names: Record<string, string> = {
        // JavaScript/TypeScript 生态
        'javascript': 'JavaScript',
        'js': 'JavaScript',
        'jsx': 'React JSX',
        'typescript': 'TypeScript',
        'ts': 'TypeScript',
        'tsx': 'React TSX',
        'vue': 'Vue Component',
        'json': 'JSON',
        
        // 样式语言
        'css': 'CSS',
        'scss': 'Sass (SCSS)',
        'sass': 'Sass',
        'less': 'Less',
        'stylus': 'Stylus',
        
        // 标记语言
        'html': 'HTML',
        'xml': 'XML',
        'svg': 'SVG',
        'markdown': 'Markdown',
        'md': 'Markdown',
        
        // 配置语言
        'yaml': 'YAML',
        'yml': 'YAML',
        'toml': 'TOML',
        'ini': 'INI',
        'env': 'Environment',
        
        // 模板语言
        'pug': 'Pug Template',
        'jade': 'Jade Template',
        'handlebars': 'Handlebars',
        'mustache': 'Mustache',
        
        // 其他前端相关
        'graphql': 'GraphQL',
        'sql': 'SQL',
        'bash': 'Bash',
        'shell': 'Shell',
        'dockerfile': 'Dockerfile',
        
        // 其他语言
        'python': 'Python',
        'java': 'Java',
        'php': 'PHP',
        'ruby': 'Ruby',
        'go': 'Go',
        'rust': 'Rust',
        'cpp': 'C++',
        'c': 'C',
        'csharp': 'C#',
        'swift': 'Swift',
        'kotlin': 'Kotlin',
        
        // 默认
        'plaintext': 'Plain Text',
        'text': 'Plain Text'
      }
      return names[lang] || lang.charAt(0).toUpperCase() + lang.slice(1)
    }
    
    const icon = getLanguageIcon(validLang)
    const blockId = `code-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`

    // 🔧 简化代码高亮逻辑，避免语言模块缺失问题
    let highlightedCode
    try {
      // 优先尝试指定语言，失败则使用自动检测
      if (validLang && validLang !== 'plaintext' && validLang !== 'text' && hljs.getLanguage(validLang)) {
        highlightedCode = hljs.highlight(code, { language: validLang }).value
      } else {
        // 使用自动检测，更安全
        highlightedCode = hljs.highlightAuto(code).value
      }
    } catch (err) {
      console.warn('代码高亮失败，使用原始代码:', err)
      // 如果高亮失败，至少保持基本的HTML转义
      highlightedCode = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    }
    
    return `
      <div class="markdown-code-block">
        <div class="markdown-code-header">
          <div class="markdown-code-info">
            <span class="markdown-code-icon">${icon}</span>
            <span class="markdown-code-lang">${getLanguageDisplayName(validLang)}</span>
          </div>
          <button class="markdown-copy-btn" onclick="copyMarkdownCode('${blockId}')">
            📋 复制
          </button>
        </div>
        <div class="markdown-code-content">
          <pre><code id="${blockId}" class="language-${validLang} hljs">${highlightedCode}</code></pre>
        </div>
      </div>
    `
  }
  
  // 自定义标题渲染 - 优化文件名显示
  renderer.heading = function(text, level) {
    const sizes = ['', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
    
    // 检查是否是文件名格式 - 支持Vue项目完整生态
    const isFileName = /\.(js|jsx|ts|tsx|vue|html|css|scss|sass|less|json|md|txt|yml|yaml|xml|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot)$|package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml|\.env|\.env\.local|\.env\.development|\.env\.production|\.gitignore|\.gitattributes|README|LICENSE|vite\.config|webpack\.config|babel\.config|eslint\.config|prettier\.config|tailwind\.config|postcss\.config|tsconfig|jsconfig|index\.|main\.|App\.|router|store|api|utils|components|views|pages|assets|public|src|dist|build|node_modules/.test(text)
    
    if (isFileName) {
      // 获取文件扩展名
      const ext = text.split('.').pop()?.toLowerCase() || ''
      const fileIcons: Record<string, string> = {
        // JavaScript/TypeScript 生态
        'js': '⚡',
        'jsx': '⚛️',
        'ts': '🔷', 
        'tsx': '🔷',
        'vue': '💚',
        'json': '📋',
        
        // 样式文件
        'css': '🎨',
        'scss': '💜',
        'sass': '💜',
        'less': '🔵',
        
        // 标记语言
        'html': '🌐',
        'xml': '📄',
        'md': '📝',
        'txt': '📝',
        
        // 配置文件
        'yml': '⚙️',
        'yaml': '⚙️',
        'env': '🔧',
        
        // 媒体文件
        'svg': '🖼️',
        'png': '🖼️',
        'jpg': '🖼️',
        'jpeg': '🖼️',
        'gif': '🖼️',
        'ico': '🖼️',
        
        // 字体文件
        'woff': '🔤',
        'woff2': '🔤',
        'ttf': '🔤',
        'eot': '🔤',
        
        // 其他语言
        'py': '🐍',
        'java': '☕',
        'php': '🐘',
        'rb': '💎',
        'go': '🐹',
        'rs': '🦀',
        'cpp': '⚙️',
        'c': '⚙️',
        'h': '⚙️'
      }
      
      // 特殊文件名处理
      const specialFiles: Record<string, string> = {
        'package.json': '📦',
        'package-lock.json': '🔒',
        'yarn.lock': '🧶',
        'pnpm-lock.yaml': '📌',
        'vite.config': '⚡',
        'webpack.config': '📦',
        'babel.config': '🔄',
        'eslint.config': '✅',
        'prettier.config': '💅',
        'tailwind.config': '🎨',
        'postcss.config': '🎨',
        'tsconfig': '🔷',
        'jsconfig': '⚡',
        'README': '📖',
        'LICENSE': '📜',
        '.gitignore': '🚫',
        '.gitattributes': '📝',
        '.env': '🔧',
        '.env.local': '🔧',
        '.env.development': '🔧',
        '.env.production': '🔧'
      }
      
      // 优先匹配特殊文件名，然后是扩展名
      const icon = specialFiles[text] || specialFiles[text.toLowerCase()] || fileIcons[ext] || '📄'
      
      // 根据文件类型确定样式主题
      const getFileTheme = (filename: string, ext: string) => {
        if (specialFiles[filename] || specialFiles[filename.toLowerCase()]) return 'special'
        if (['js', 'jsx', 'ts', 'tsx'].includes(ext)) return 'script'
        if (['vue'].includes(ext)) return 'vue'
        if (['css', 'scss', 'sass', 'less'].includes(ext)) return 'style'
        if (['html', 'xml'].includes(ext)) return 'markup'
        if (['json', 'yml', 'yaml'].includes(ext)) return 'config'
        if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'ico'].includes(ext)) return 'media'
        return 'default'
      }
      
      const theme = getFileTheme(text, ext)
      
      // 获取文件标签文本
      const getFileBadgeText = (ext: string, filename: string) => {
        if (filename.includes('package.json')) return 'Package'
        if (filename.includes('vite.config')) return 'Vite Config'
        if (filename.includes('tsconfig')) return 'TypeScript Config'
        if (filename.includes('.env')) return 'Environment'
        if (filename.includes('README')) return 'Documentation'
        if (['js', 'jsx'].includes(ext)) return 'JavaScript'
        if (['ts', 'tsx'].includes(ext)) return 'TypeScript'
        if (ext === 'vue') return 'Vue Component'
        if (['css', 'scss', 'sass', 'less'].includes(ext)) return 'Stylesheet'
        if (ext === 'html') return 'HTML'
        if (ext === 'json') return 'JSON'
        if (['yml', 'yaml'].includes(ext)) return 'YAML'
        if (['png', 'jpg', 'jpeg', 'gif', 'svg'].includes(ext)) return 'Image'
        return 'File'
      }
      
      return `<div class="file-header file-theme-${theme} markdown-heading markdown-${sizes[level]}">
        <span class="file-icon">${icon}</span>
        <span class="file-name">${text}</span>
        <span class="file-badge file-badge-${theme}">${getFileBadgeText(ext, text)}</span>
      </div>`
    }
    
    return `<div class="markdown-heading markdown-${sizes[level]}">${text}</div>`
  }
  
  // 自定义段落渲染
  renderer.paragraph = function(text) {
    return `<div class="markdown-paragraph">${text}</div>`
  }
  
  // 自定义列表项渲染
  renderer.listitem = function(text) {
    return `<li class="markdown-list-item">${text}</li>`
  }
  
  return renderer
}

/**
 * 格式化消息内容，正确处理文本和代码块
 */
const formatMessageContent = (content: string): string => {
  if (!content) return ''
  
  // 检查content是否为字符串
  if (typeof content !== 'string') {
    console.warn('content不是字符串:', typeof content, content)
    return `<div class="debug-content">内容类型错误: ${typeof content}</div>`
  }
  
  try {
    // HTML转义函数
    const escapeHtml = (text: string) => {
      return text
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#x27;')
    }
    
    // 🔧 优化流式内容处理 - 处理不完整的代码块
    const codeBlocks: string[] = []
    const codeBlockPlaceholder = 'CODE_BLOCK_PLACEHOLDER_'
    
    // 处理完整的代码块
    let processedContent = content.replace(
      /```(\w+)?\s*\n([\s\S]*?)\n```/g,
      (match, language, code) => {
        const lang = language || 'text'
        const escapedCode = escapeHtml(code.trim())
        
        // 获取语言图标
        const getIcon = (lang: string) => {
          const icons: Record<string, string> = {
            'html': '🌐',
            'css': '🎨',
            'javascript': '⚡',
            'js': '⚡'
          }
          return icons[lang.toLowerCase()] || '📝'
        }
        
        const codeBlockHtml = `<div class="distinct-code-block">
          <div class="distinct-code-header">
            <span class="code-info">
              <span class="code-icon">${getIcon(lang)}</span>
              <span class="code-lang">${lang.toUpperCase()}</span>
            </span>
            <button onclick="copyCodeText(this)" data-code="${escapeHtml(code.trim())}" class="distinct-copy-btn">
              📋 复制
            </button>
          </div>
          <div class="distinct-code-content">
            <pre><code class="language-${lang.toLowerCase()}">${escapedCode}</code></pre>
          </div>
        </div>`
        
        const index = codeBlocks.length
        codeBlocks.push(codeBlockHtml)
        return codeBlockPlaceholder + index
      }
    )

    // 🔧 处理不完整的代码块（流式输出中）
    processedContent = processedContent.replace(
      /```(\w+)?\s*\n([\s\S]+)$/,
      (match, language, code) => {
        const lang = language || 'text'
        const escapedCode = escapeHtml(code)
        
        return `<div class="incomplete-code-block">
          <div class="code-header">
            <span class="code-lang">${lang.toUpperCase()}</span>
            <span class="streaming-indicator">正在输入...</span>
          </div>
          <pre class="code-content"><code>${escapedCode}</code></pre>
        </div>`
      }
    )
    
    // 处理文本内容
    const lines = processedContent.split('\n')
    const processedLines: string[] = []
    
    for (const line of lines) {
      const trimmedLine = line.trim()
      
      // 检查是否是代码块占位符
      if (trimmedLine.startsWith(codeBlockPlaceholder)) {
        const index = parseInt(trimmedLine.replace(codeBlockPlaceholder, ''))
        if (codeBlocks[index]) {
          processedLines.push(codeBlocks[index])
        }
        continue
      }

      // 🔧 处理特殊格式标记
      if (trimmedLine.startsWith('[选择工具]') || trimmedLine.startsWith('[工具调用]')) {
        processedLines.push(`<div class="tool-marker">${escapeHtml(trimmedLine)}</div>`)
        continue
      }

      // 处理加粗文本 **text**
      if (trimmedLine.startsWith('**') && trimmedLine.endsWith('**') && trimmedLine.length > 4) {
        const boldText = trimmedLine.substring(2, trimmedLine.length - 2)
        processedLines.push(`<div class="bold-text">${escapeHtml(boldText)}</div>`)
        continue
      }
      
      // 空行 - 减少空行间距
      if (!trimmedLine) {
        // 避免连续空行
        if (processedLines.length > 0 && !processedLines[processedLines.length - 1].includes('empty-line')) {
          processedLines.push('<div class="empty-line"></div>')
        }
        continue
      }
      
      // 标题处理
      if (trimmedLine.startsWith('# ')) {
        const title = trimmedLine.substring(2).trim()
        processedLines.push(`<div class="clean-title">${escapeHtml(title)}</div>`)
        continue
      }
      
      // 列表项处理
      if (trimmedLine.match(/^\d+\.\s/) || trimmedLine.startsWith('- ') || trimmedLine.startsWith('* ')) {
        processedLines.push(`<div class="clean-list-item">${escapeHtml(trimmedLine)}</div>`)
        continue
      }
      
      // 普通段落
      processedLines.push(`<div class="clean-paragraph">${escapeHtml(trimmedLine)}</div>`)
    }
    
    const result = `<div class="clean-content">${processedLines.join('')}</div>`
    
    // 🔧 立即应用代码高亮，移除延迟
    nextTick(() => {
      if (typeof window !== 'undefined' && (window as any).hljs) {
        document.querySelectorAll('.distinct-code-content pre code:not(.hljs)').forEach((block) => {
          try {
            ;(window as any).hljs.highlightElement(block)
          } catch (e) {
            console.warn('代码高亮失败:', e)
          }
        })
      }
    })
    
    return result
    
  } catch (error) {
    console.error('格式化失败:', error)
    return `<div class="error-content">格式化失败: ${error}</div>`
  }
}

// 🔧 性能优化：节流变量
let highlightTimer: NodeJS.Timeout | null = null
let lastHighlightTime = 0
const HIGHLIGHT_THROTTLE_MS = 50 // 减少到50ms节流间隔，提升实时性

/**
 * 🚀 节流更新消息内容 - 优化长内容性能
 */
const updateMessageContentThrottled = (message: any, newData: string) => {
  // 直接更新内容到缓冲区
  contentBuffer += newData
  
  const now = Date.now()
  const timeSinceLastRender = now - lastRenderTime
  
  // 🔧 长内容检测：如果内容过长，增加渲染间隔，但为代码块保持更高频率
  const currentLength = (message.content || '').length + contentBuffer.length
  const fullContent = (message.content || '') + contentBuffer
  
  // 🔧 检测各种代码块类型，包括特殊语言
  const hasCodeBlock = fullContent.includes('```')
  const hasSpecialCodeBlock = fullContent.includes('```vue') || 
                              fullContent.includes('```jsx') || 
                              fullContent.includes('```tsx') || 
                              fullContent.includes('```py') || 
                              fullContent.includes('```ts')
  
  // 根据代码块类型调整渲染频率
  let dynamicThrottle = RENDER_THROTTLE_MS
  if (hasSpecialCodeBlock) {
    dynamicThrottle = 5 // 特殊语言代码块超快渲染，只延迟5ms
  } else if (hasCodeBlock) {
    dynamicThrottle = 10 // 普通代码块快速渲染，延迟10ms
  } else if (currentLength > MAX_CONTENT_LENGTH) {
    dynamicThrottle = RENDER_THROTTLE_MS * 2
  }
  
  // 清除之前的更新定时器
  if (contentUpdateTimer) {
    clearTimeout(contentUpdateTimer)
  }
  
  // 如果距离上次渲染时间太短，延迟执行
  if (timeSinceLastRender < dynamicThrottle) {
    contentUpdateTimer = setTimeout(() => {
      flushContentBuffer(message)
    }, dynamicThrottle - timeSinceLastRender)
  } else {
    // 立即执行
    flushContentBuffer(message)
  }
}

/**
 * 🔧 刷新内容缓冲区到UI
 */
const flushContentBuffer = (message: any) => {
  if (contentBuffer) {
    message.content = (message.content || '') + contentBuffer
    
    console.log(`💾 缓冲区刷新: +${contentBuffer.length} 字符，总长度: ${message.content.length}`)
    
    // 长内容警告
    if (message.content.length > MAX_CONTENT_LENGTH) {
      console.warn(`⚠️ 内容长度超过阈值: ${message.content.length}/${MAX_CONTENT_LENGTH}`)
    }
    
    contentBuffer = ''
    lastRenderTime = Date.now()
  }
}

/**
 * 🚀 优化的代码高亮函数 - 确保实时流式显示
 */
const throttledCodeHighlight = () => {
  const now = Date.now()
  
  // 清除之前的定时器
  if (highlightTimer) {
    clearTimeout(highlightTimer)
  }
  
  // 如果距离上次高亮时间太短，但仍然快速执行以保证实时性
  const timeSinceLastHighlight = now - lastHighlightTime
  if (timeSinceLastHighlight < HIGHLIGHT_THROTTLE_MS) {
    // 很短的延迟，保证实时性
    highlightTimer = setTimeout(() => {
      applyCodeHighlight()
      lastHighlightTime = Date.now()
    }, 10) // 只延迟10ms，几乎是立即执行
  } else {
    // 立即执行
    applyCodeHighlight()
    lastHighlightTime = now
  }
}

/**
 * 🎨 应用代码高亮 - 增强性能版本
 */
const applyCodeHighlight = () => {
  // 确保hljs已加载
  if (typeof window !== 'undefined' && (window as any).hljs) {
    // 🔧 优化：只查找当前最新的AI消息中的代码块，减少DOM查询范围
    const streamingAIMessage = messages.value
      .slice()
      .reverse()
      .find(msg => msg.role === 'ai' && msg.isStreaming)
    
    if (streamingAIMessage) {
      // 🔧 更精确的选择器：只处理当前流式消息的代码块
      const messageElement = document.querySelector(`[data-message-id="${streamingAIMessage.id}"]`)
      if (messageElement) {
        const codeBlocks = messageElement.querySelectorAll('pre code:not(.hljs)')
        
        if (codeBlocks.length > 0) {
          console.log(`🎨 应用代码高亮，当前消息找到 ${codeBlocks.length} 个新代码块`)
          
          codeBlocks.forEach((block, index) => {
      try {
        ;(window as any).hljs.highlightElement(block)
              console.log(`✅ 流式消息代码块 ${index + 1} 高亮完成`)
      } catch (error) {
              console.warn(`❌ 流式消息代码块 ${index + 1} 高亮失败:`, error)
            }
          })
        }
      }
    } else {
      // 🔧 备用方案：如果没有流式消息，则使用全局查找（但添加数量限制）
      const codeBlocks = document.querySelectorAll('.markdown-content pre code:not(.hljs), .ai-code-content pre code:not(.hljs)')
      const maxBlocks = Math.min(codeBlocks.length, 10) // 最多处理10个代码块，避免性能问题
      
      if (maxBlocks > 0) {
        console.log(`🎨 备用代码高亮，处理 ${maxBlocks}/${codeBlocks.length} 个代码块`)
        
        for (let i = 0; i < maxBlocks; i++) {
          const block = codeBlocks[i]
          try {
            ;(window as any).hljs.highlightElement(block)
          } catch (error) {
            console.warn(`❌ 代码块 ${i + 1} 高亮失败:`, error)
          }
        }
      }
    }
  } else {
    console.warn('⚠️ hljs未加载，跳过代码高亮')
  }
}

// 添加全局复制函数
declare global {
  interface Window {
    copyToClipboard: (button: HTMLElement) => void
    copyCodeToClipboard: (blockId: string) => void
    copyMarkdownCode: (blockId: string) => void
    copyCodeText: (button: HTMLElement) => void
    highlightDebounce?: NodeJS.Timeout
  }
}

window.copyToClipboard = (button: HTMLElement) => {
  const code = button.getAttribute('data-code')
  if (code) {
    navigator.clipboard.writeText(code).then(() => {
      const originalText = button.textContent
      button.textContent = '已复制'
      setTimeout(() => {
        button.textContent = originalText
      }, 2000)
    }).catch(() => {
      console.error('复制失败')
    })
  }
}

window.copyCodeToClipboard = (blockId: string) => {
  const codeElement = document.getElementById(blockId)
  if (codeElement) {
    const code = codeElement.textContent || ''
    navigator.clipboard.writeText(code).then(() => {
      // 找到复制按钮并更新文本
      const button = codeElement.closest('.clean-code-block')?.querySelector('.clean-copy-btn')
      if (button) {
        const originalText = button.textContent
        button.textContent = '✅ 已复制'
        setTimeout(() => {
          button.textContent = originalText
        }, 2000)
      }
    }).catch(() => {
      console.error('复制失败')
    })
  }
}

window.copyMarkdownCode = (blockId: string) => {
  const codeElement = document.getElementById(blockId)
  if (codeElement) {
    const code = codeElement.textContent || ''
    navigator.clipboard.writeText(code).then(() => {
      // 找到复制按钮并更新文本
      const button = codeElement.closest('.markdown-code-block')?.querySelector('.markdown-copy-btn')
      if (button) {
        const originalText = button.textContent
        button.textContent = '✅ 已复制'
        setTimeout(() => {
          button.textContent = originalText
        }, 2000)
      }
    }).catch(() => {
      console.error('复制失败')
    })
  }
}

window.copyCodeText = (button: HTMLElement) => {
  const code = button.getAttribute('data-code')
  if (code) {
    navigator.clipboard.writeText(code).then(() => {
      const originalText = button.textContent
      button.textContent = '✅ 已复制'
      setTimeout(() => {
        button.textContent = originalText
      }, 2000)
    }).catch(() => {
      console.error('复制失败')
    })
  }
}

// 页面初始化
onMounted(() => {
  console.log('=== 对话页面初始化 ===')
  console.log('路由参数:', route.params)

  // 🔧 关键修复：只清理无效的SSE连接，不影响正在进行的对话
  if (eventSource) {
    // 检查是否有对应的流式AI消息
    const hasStreamingAI = messages.value.some(msg => msg.role === 'ai' && msg.isStreaming)
    
    if (hasStreamingAI) {
      console.log('检测到SSE连接和流式AI消息，保持连接')
    } else {
      console.warn('检测到无效的SSE连接（无对应流式AI消息），正在清理...')
      eventSource.close()
      eventSource = null
      sendLoading.value = false
    }
  } else {
    console.log('无SSE连接需要清理')
  }
  
  console.log('SSE连接检查完成')

  // 对于新页面，先设置合理的初始状态，避免显示不必要的加载提示
  // 这些状态会在loadChatHistory中根据实际情况更新
  historyLoaded.value = false  // 将在loadChatHistory完成后设置为true
  hasMoreHistory.value = false // 默认没有更多历史，有的话会在loadChatHistory中更新

  // 初始化Markdown配置
  configureMarked()

  // 获取应用信息
  fetchAppInfo()
})
</script>

<template>
  <div class="app-chat-page">
    <!-- 顶部工具栏 -->
    <div class="chat-header">
      <div class="header-left">
        <div class="title-section">
          <div class="title-content">
        <h1 class="app-title">{{ app.appName || '新应用' }}</h1>
            <a-tag 
              v-if="app.codeGenType" 
              :color="getTypeColor(app.codeGenType)"
              class="type-tag"
            >
              {{ getCodeGenTypeName(app.codeGenType) }}
            </a-tag>
          </div>
          <a-dropdown
            v-if="!appLoading && app.id"
            :trigger="['click']"
            placement="bottomLeft"
          >
            <a-button
              type="text"
              size="small"
              class="panel-toggle-btn"
            >
              <template #icon><DownOutlined /></template>
            </a-button>
            <template #overlay>
              <div class="panel-dropdown">
                <!-- 基础信息 -->
                <div class="info-section">
                  <h4>基础信息</h4>
                  <div class="info-item">
                    <label>创建者</label>
                    <div class="creator-info">
                      <a-avatar :src="app.user?.userAvatar" :size="20" />
                      <span>{{ app.user?.userName || '未知用户' }}</span>
                    </div>
                  </div>
                  <div class="info-item">
                    <label>创建时间</label>
                    <span>{{ formatDate(app.createTime) }}</span>
                  </div>
                </div>

                <!-- 功能按钮 -->
                <div class="action-section">
                  <div class="action-item" @click="handleViewWork" v-if="app.deployKey">
                    <EyeOutlined />
                    <span>查看作品</span>
                  </div>
                  <div class="action-item" @click="handleSettings" v-if="canEdit">
                    <SettingOutlined />
                    <span>作品设置</span>
                  </div>
                  <div class="action-item danger" @click="handleDeleteApp" v-if="canEdit">
                    <DeleteOutlined />
                    <span>删除作品</span>
                  </div>
                </div>
              </div>
            </template>
          </a-dropdown>
        </div>
      </div>
      <div class="header-right">
        <a-space>
            <a-tooltip title="查看应用详细信息">
              <a-button
                @click="goToAppDetail"
                :loading="appLoading"
                type="default"
              >
                <template #icon><InfoCircleOutlined /></template>
                应用详情
              </a-button>
            </a-tooltip>
            <a-tooltip title="下载应用源代码">
              <a-button
                type="default"
                :loading="downloadLoading"
                @click="handleDownload"
                :disabled="downloadLoading"
              >
                <template #icon><DownloadOutlined /></template>
                下载代码
              </a-button>
            </a-tooltip>
            <a-tooltip title="将应用部署到互联网">
        <a-button 
          type="primary" 
          :loading="deployLoading"
          @click="handleDeploy"
                :disabled="deployLoading"
        >
          <template #icon><RocketOutlined /></template>
                部署
        </a-button>
            </a-tooltip>
        </a-space>
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div class="chat-content">
      <!-- 对话区域 -->
      <div class="chat-panel" :class="{ 'resizing': isResizing }" :style="{ width: chatWidth + '%' }">
        <!-- 消息区域 -->
        <div class="messages-container" ref="messagesContainer">
          <!-- 加载更多按钮 -->
          <div v-if="hasMoreHistory" class="load-more-container">
            <a-button type="link" @click="loadChatHistory(true)" :loading="historyLoading" size="small">
              加载更多历史消息
            </a-button>
          </div>
          
          <!-- 回到底部按钮 -->
          <div 
            v-if="showScrollToBottomButton" 
            class="scroll-to-bottom-button"
            @click="handleScrollToBottom"
          >
            <a-button type="primary" shape="circle" size="large">
              <template #icon>
                <DownOutlined />
              </template>
            </a-button>
            </div>
          <div v-for="(message, index) in messages" :key="index" class="message-item" :data-message-id="message.id">
            <div v-if="message.role === 'user'" class="user-message">
              <div class="message-content">{{ message.content }}</div>
              <div class="message-avatar">
                <a-avatar :src="loginUserStore.loginUser.userAvatar" />
          </div>
            </div>
            <div v-else class="ai-message">
              <div class="message-avatar">
                <a-avatar :src="logoImg" />
              </div>
              <div class="message-content">
                <MarkdownRenderer 
                  v-if="message.content" 
                  :content="message.content"
                  :key="`msg-${message.id}-${message.content.length}-${message.content.slice(-5).replace(/[^a-zA-Z0-9]/g, '_')}`"
                />
                <div v-if="message.isStreaming && !message.content" class="loading-indicator">
                  <a-spin size="small" />
                  <span>AI 正在思考...</span>
                </div>
                <!-- Vue项目生成的特殊加载提示 -->
                <div v-if="message.isStreaming && message.content && message.content.includes('正在创建Vue项目')" class="vue-project-loading">
                  <div class="vue-loading-animation">
                    <a-spin size="large" />
                  </div>
                  <div class="vue-loading-tips">
                    <h4>🚀 Vue项目生成中</h4>
                    <p>正在创建多个文件，预计需要更长时间，请耐心等待...</p>
                    <div class="loading-steps">
                      <div class="step">📁 创建项目结构</div>
                      <div class="step">⚙️ 配置依赖项</div>
                      <div class="step">🎨 生成组件文件</div>
                      <div class="step">🔧 优化代码结构</div>
                    </div>
                  </div>
                </div>
                  </div>
                </div>
                </div>
              </div>

        <!-- 选中元素信息显示 -->
        <div v-if="selectedElement" class="selected-element-info">
          <a-alert
            :message="`已选中元素: ${formatElementDescription(selectedElement)}`"
            type="info"
            show-icon
            closable
            @close="removeSelectedElement"
          >
            <template #description>
              <div class="element-details">
                <div><strong>标签:</strong> {{ selectedElement.tagName.toLowerCase() }}</div>
                <div v-if="selectedElement.id"><strong>ID:</strong> {{ selectedElement.id }}</div>
                <div v-if="selectedElement.className"><strong>类名:</strong> {{ selectedElement.className }}</div>
                <div v-if="selectedElement.selector"><strong>选择器:</strong> {{ selectedElement.selector }}</div>
            </div>
            </template>
          </a-alert>
        </div>

        <!-- 用户消息输入框 -->
          <div class="input-container">
          <a-tooltip v-if="!canEdit" title="无法在别人的作品下对话哦~" placement="top">
            <div class="input-wrapper" style="position: relative !important; display: block !important; width: 100% !important; overflow: visible !important;">
            <a-textarea
              v-model:value="messageInput"
                :placeholder="getInputPlaceholder()"
                :rows="4"
                :maxlength="1000"
                @keydown.enter.prevent="sendMessageWithVisualEdit"
                :disabled="sendLoading || !canEdit"
              />
              <div class="input-actions" style="position: absolute !important; bottom: 16px !important; right: 16px !important; z-index: 1000 !important;">
                <a-button
                  type="primary"
                  @click="sendMessageWithVisualEdit"
                  :loading="sendLoading"
                  :disabled="!canEdit || !messageInput.trim()"
                  shape="circle"
                  style="width: 36px !important; height: 36px !important; border-radius: 50% !important; padding: 0 !important;"
                >
                  <template #icon>
                    <SendOutlined />
                  </template>
                </a-button>
              </div>
            </div>
          </a-tooltip>
          <div v-else class="input-wrapper" style="position: relative !important; display: block !important; width: 100% !important; overflow: visible !important;">
            <a-textarea
              v-model:value="messageInput"
              :placeholder="getInputPlaceholder()"
              :rows="4"
              :maxlength="1000"
              @keydown.enter.prevent="sendMessageWithVisualEdit"
              :disabled="sendLoading"
            />
            <div class="input-actions" style="position: absolute !important; bottom: 16px !important; right: 16px !important; z-index: 1000 !important;">
            <a-button
              type="primary"
                @click="sendMessageWithVisualEdit"
              :loading="sendLoading"
                :disabled="!canEdit || !messageInput.trim()"
                shape="circle"
                style="width: 36px !important; height: 36px !important; border-radius: 50% !important; padding: 0 !important;"
            >
                <template #icon>
                  <SendOutlined />
                </template>
            </a-button>
            </div>
          </div>
        </div>
      </div>

      <!-- 可拖拽分隔条 -->
      <div
        class="resize-handle"
        @mousedown="startResize"
        @dblclick="resetPanelWidth"
        :class="{ 'resizing': isResizing }"
        title="拖拽调整大小，双击重置为默认比例"
      >
        <div class="resize-line"></div>
      </div>

      <!-- 右侧网站预览区域 - 可调节宽度 -->
      <div class="preview-panel" :class="{ 'resizing': isResizing }" :style="{ width: previewWidth + '%' }">
        <div v-if="showPreview" class="website-preview">
          <div class="preview-header">
            <h3>生成的网页展示</h3>
            <div class="preview-actions">
              <!-- 可视化编辑按钮 -->
              <a-tooltip :title="isEditMode ? '退出编辑模式' : '进入可视化编辑模式'">
                <a-button 
                  size="small" 
                  :type="isEditMode ? 'primary' : 'default'"
                  @click="toggleEditMode"
                  :disabled="!showPreview"
                  class="edit-button"
                >
                  <template #icon><EditOutlined /></template>
                  {{ isEditMode ? '退出编辑' : '编辑网页' }}
                </a-button>
              </a-tooltip>
              
              <a-tooltip title="重新加载预览内容">
              <a-button size="small" @click="showWebsitePreview">
                刷新预览
              </a-button>
              </a-tooltip>
            </div>
          </div>
          <div class="preview-content" :class="{ 'edit-mode': isEditMode }">
            <iframe
              id="website-preview"
              :src="previewUrl"
              frameborder="0"
              class="preview-iframe"
              sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
              @load="onPreviewLoad"
              @error="onPreviewError"
            ></iframe>
            <!-- 编辑模式浮动指示器 -->
            <div v-if="isEditMode" class="edit-mode-badge">
              <div class="badge-content">
                <EditOutlined class="badge-icon" />
                <span class="badge-text">编辑</span>
              </div>
              <div class="badge-tip">点击元素编辑</div>
            </div>
          </div>
        </div>
        
        <div v-else class="preview-placeholder">
          <div class="placeholder-content">
            <RobotOutlined class="placeholder-icon" />
            <h3>网站预览</h3>
            <p>AI正在为您生成网站，请稍候...</p>
            <a-tooltip title="手动加载预览内容">
            <a-button 
              v-if="app.id" 
              type="primary" 
              @click="showWebsitePreview"
              style="margin-top: 16px"
            >
              手动刷新预览
            </a-button>
            </a-tooltip>
          </div>
        </div>
      </div>
    </div>
  </div>


  <!-- 部署成功弹窗 -->
  <a-modal
    v-model:open="deploySuccessVisible"
    title="部署成功"
    :footer="null"
    width="500px"
    centered
  >
    <div class="deploy-success-content">
      <div class="success-icon">
        <CheckCircleFilled style="font-size: 60px; color: #52c41a;" />
      </div>
      <h3>网站部署成功！</h3>
      <p>您的网站已经成功部署，可以通过以下链接访问：</p>

      <div class="url-section">
        <a-input
          :value="deployedUrl"
          readonly
          class="deploy-url-input"
        >
          <template #suffix>
            <a-tooltip title="复制链接">
              <a-button
                type="text"
                size="small"
                @click="copyDeployUrl"
              >
                <template #icon><CopyOutlined /></template>
              </a-button>
            </a-tooltip>
          </template>
        </a-input>
      </div>

      <div class="modal-actions">
        <a-space>
          <a-button @click="deploySuccessVisible = false">关闭</a-button>
          <a-button type="primary" @click="visitDeployedSite">访问网站</a-button>
        </a-space>
      </div>
    </div>
  </a-modal>
</template>

<style scoped>
.app-chat-page {
  height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  margin: -24px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

/* 顶部工具栏 */
.chat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(232, 232, 232, 0.8);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  position: relative;
  z-index: 10;
}

.header-left .app-title {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  color: #262626;
}

.app-id-debug {
  font-size: 12px;
  color: #999;
  margin-left: 10px;
  padding: 2px 8px;
  background: #f0f0f0;
  border-radius: 4px;
}

/* 主要内容区域 */
.chat-content {
  flex: 1;
  display: flex;
  overflow: hidden;
  gap: 0;
  padding: 0;
}


/* 标题区域样式 */
.title-section {
  display: flex;
  align-items: center;
  gap: 8px;
}

.panel-toggle-btn {
  opacity: 0.6;
  transition: all 0.2s;
}

.panel-toggle-btn:hover {
  opacity: 1;
  color: #1890ff;
}

/* 应用功能面板下拉样式 */
.panel-dropdown {
  width: 280px;
  padding: 16px;
  background: white;
  border-radius: 6px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.panel-dropdown .info-section {
  margin-bottom: 20px;
}

.panel-dropdown .info-section h4 {
  font-size: 14px;
  font-weight: 600;
  color: #262626;
  margin: 0 0 12px 0;
  padding-bottom: 6px;
  border-bottom: 1px solid #f0f0f0;
}

.panel-dropdown .info-item {
  margin-bottom: 10px;
}

.panel-dropdown .info-item label {
  display: block;
  font-size: 12px;
  color: #8c8c8c;
  margin-bottom: 4px;
}

.panel-dropdown .info-item span {
  font-size: 13px;
  color: #262626;
}

.panel-dropdown .creator-info {
  display: flex;
  align-items: center;
  gap: 6px;
}

.panel-dropdown .creator-info span {
  font-size: 13px;
  color: #262626;
}

.panel-dropdown .action-section {
  border-top: 1px solid #f0f0f0;
  padding-top: 12px;
}

.panel-dropdown .action-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  cursor: pointer;
  color: #595959;
  border-radius: 4px;
  transition: all 0.2s;
  margin-bottom: 2px;
}

.panel-dropdown .action-item:hover {
  background: #f5f5f5;
  color: #1890ff;
}

.panel-dropdown .action-item.danger {
  color: #ff4d4f;
}

.panel-dropdown .action-item.danger:hover {
  background: #fff2f0;
  color: #ff4d4f;
}

.panel-dropdown .action-item span {
  font-size: 13px;
}

/* 部署成功弹窗样式 */
.deploy-success-content {
  text-align: center;
  padding: 20px 0;
}

.success-icon {
  margin-bottom: 16px;
}

.deploy-success-content h3 {
  font-size: 20px;
  font-weight: 600;
  color: #262626;
  margin: 16px 0;
}

.deploy-success-content p {
  color: #595959;
  margin-bottom: 24px;
}

.url-section {
  margin-bottom: 32px;
}

.deploy-url-input {
  font-family: 'Monaco', 'Consolas', monospace;
}

.modal-actions {
  display: flex;
  justify-content: center;
}

/* 对话面板 */
.chat-panel {
  display: flex;
  flex-direction: column;
  background: white;
  border-right: 1px solid #e8e8e8;
  flex-shrink: 0;
  transition: width 0.1s ease;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  background: #fafafa;
  max-height: calc(100vh - 180px);
}

/* 欢迎消息 */
.welcome-message {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  min-height: 300px;
}

.welcome-content {
  text-align: center;
  color: #8c8c8c;
}

/* 加载更多历史消息 */
.load-more-container {
  display: flex;
  justify-content: center;
  padding: 16px;
  margin-bottom: 16px;
}

.load-more-btn {
  color: #666;
  transition: all 0.2s ease;
}

.load-more-btn:hover {
  color: #1890ff;
  background-color: rgba(24, 144, 255, 0.04);
}

.welcome-icon {
  font-size: 48px;
  color: #1890ff;
  margin-bottom: 16px;
}

.welcome-content h3 {
  margin-bottom: 8px;
  color: #595959;
}

/* 消息样式 */
.message-item {
  margin-bottom: 24px;
}





.message-text {
  line-height: 1.5;
  white-space: pre-wrap;
}

.message-text pre {
  margin: 0;
  font-family: inherit;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.streaming-content {
  line-height: 1.5;
  white-space: pre-wrap;
}

.streaming-content pre {
  margin: 0;
  font-family: inherit;
  white-space: pre-wrap;
  word-wrap: break-word;
  display: inline;
}

.cursor-blink {
  display: inline-block;
  background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
  width: 3px;
  height: 18px;
  animation: blink 1.2s infinite;
  margin-left: 3px;
  border-radius: 2px;
  vertical-align: text-bottom;
}

@keyframes blink {
  0%, 45% {
    opacity: 1;
    transform: scaleY(1);
  }
  50%, 95% {
    opacity: 0.3;
    transform: scaleY(0.8);
  }
  100% {
    opacity: 1;
    transform: scaleY(1);
  }
}

/* 流式输出动画 */
.streaming-content {
  animation: fadeInUp 0.3s ease-out;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}







/* 拖拽分隔条 */
.resize-handle {
  width: 12px;
  background: transparent;
  cursor: col-resize;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border-left: 1px solid #f0f0f0;
  border-right: 1px solid #f0f0f0;
  z-index: 10;
}

.resize-handle:hover {
  background: rgba(24, 144, 255, 0.04);
  border-color: rgba(24, 144, 255, 0.2);
}

.resize-handle.resizing {
  background: rgba(24, 144, 255, 0.08);
  border-color: #40a9ff;
}

.resize-line {
  width: 3px;
  height: 50px;
  background: #e0e0e0;
  border-radius: 2px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 0.6;
}

.resize-handle:hover .resize-line {
  background: #40a9ff;
  height: 70px;
  opacity: 1;
  box-shadow: 0 2px 8px rgba(64, 169, 255, 0.3);
}

.resize-handle.resizing .resize-line {
  background: #1890ff;
  height: 90px;
  opacity: 1;
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
  transform: scaleX(1.2);
}

/* 添加拖拽时的视觉反馈 */
.resize-handle::before {
  content: '';
  position: absolute;
  left: -8px;
  right: -8px;
  top: 0;
  bottom: 0;
  background: transparent;
}

.resize-handle:hover::before {
  background: rgba(24, 144, 255, 0.02);
}

/* 拖拽时的全局样式 */
body.resizing {
  cursor: col-resize !important;
}

body.resizing * {
  cursor: col-resize !important;
}

/* 添加平滑的宽度变化动画 */
.chat-panel,
.preview-panel {
  transition: width 0.1s ease-out;
}

.chat-panel.resizing,
.preview-panel.resizing {
  transition: none;
}

/* 右侧预览面板 */
.preview-panel {
  background: white;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  transition: width 0.1s ease;
}

.website-preview {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 20px;
  border-bottom: 1px solid #e8e8e8;
  background: #fafafa;
  flex-shrink: 0;
}

.preview-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #262626;
}

.preview-content {
  flex: 1;
  position: relative;
}

.preview-iframe {
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 0 0 8px 8px;
  transition: opacity 0.3s ease;
}

.preview-iframe:not([src]) {
  opacity: 0.5;
}

/* 预览占位符 */
.preview-placeholder {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #fafafa;
}

.placeholder-content {
  text-align: center;
  color: #8c8c8c;
}

.placeholder-icon {
  font-size: 64px;
  color: #d9d9d9;
  margin-bottom: 16px;
}

.placeholder-content h3 {
  margin-bottom: 8px;
  color: #595959;
}

/* 响应式设计 - 移除固定宽度，让拖拽控制宽度 */

@media (max-width: 1024px) {
  .chat-content {
    flex-direction: column;
  }
  
  .chat-panel {
    width: 100% !important;
    height: 55%;
    border-right: none;
    border-bottom: 1px solid #e8e8e8;
  }
  
  .preview-panel {
    width: 100% !important;
    height: 45%;
    border-right: none;
    border-top: none;
  }

  .resize-handle {
    display: none;
  }
}

@media (max-width: 768px) {
  .chat-header {
    padding: 12px 16px;
    flex-wrap: wrap;
    gap: 8px;
  }
  
  .header-left .app-title {
    font-size: 18px;
  }

  .header-right {
    flex-wrap: wrap;
  }
  
  .chat-messages {
    padding: 16px;
  }
  
  
  .message-content {
    max-width: 90%;
  }
  
  .preview-header {
    padding: 12px 16px;
  }

  .chat-panel {
    height: 60%;
  }

  .preview-panel {
    height: 40%;
  }
}

/* AI代码块增强样式 */
.ai-code-block {
  margin: 16px 0;
  border-radius: 12px;
  border: 1px solid #e1e5e9;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  transition: all 0.2s ease;
}

.ai-code-block:hover {
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
  transform: translateY(-1px);
}

.ai-code-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  color: #2d3748;
  font-weight: 600;
}

.ai-code-info {
  display: flex;
  align-items: center;
  gap: 10px;
}

.ai-code-icon {
  font-size: 18px;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));
}

.ai-code-language {
  font-size: 13px;
  letter-spacing: 0.8px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

.ai-copy-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  font-size: 12px;
  color: #4a5568;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s ease;
  font-weight: 500;
}

.ai-copy-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

.ai-copy-btn .copy-icon {
  font-size: 14px;
}

.ai-code-content {
  position: relative;
  border-top: 1px solid rgba(0,0,0,0.08);
}

.ai-code-content pre {
  margin: 0;
  padding: 20px;
  background: transparent;
  font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.6;
  overflow-x: auto;
  white-space: pre;
  color: #2d3748;
}

/* 简单代码高亮 */
.ai-code-content code {
  background: none;
  color: inherit;
}

/* 覆盖highlight.js默认样式 */
.ai-code-content .hljs {
  background: transparent !important;
  padding: 0 !important;
  color: #2d3748 !important;
}

/* 语言特定背景 */
.ai-code-content pre:has(.language-html) {
  background: linear-gradient(135deg, #fff5f5 0%, #fed7d7 1%, #fff5f5 100%);
}

.ai-code-content pre:has(.language-css) {
  background: linear-gradient(135deg, #f0fff4 0%, #c6f6d5 1%, #f0fff4 100%);
}

.ai-code-content pre:has(.language-javascript),
.ai-code-content pre:has(.language-js) {
  background: linear-gradient(135deg, #fffbeb 0%, #fed7aa 1%, #fffbeb 100%);
}

.ai-code-content pre:has(.language-typescript),
.ai-code-content pre:has(.language-ts) {
  background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 1%, #eff6ff 100%);
}

/* highlight.js 语法高亮颜色优化 */
.ai-code-content .hljs-keyword {
  color: #d73a49 !important;
  font-weight: 600;
}

.ai-code-content .hljs-string {
  color: #032f62 !important;
}

.ai-code-content .hljs-comment {
  color: #6a737d !important;
  font-style: italic;
}

.ai-code-content .hljs-number {
  color: #005cc5 !important;
}

.ai-code-content .hljs-attr {
  color: #e36209 !important;
}

.ai-code-content .hljs-tag {
  color: #22863a !important;
}

/* AI专用增强样式 */

/* 文件头样式 */
.ai-file-header {
  display: inline-block;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  margin: 16px 0 8px 0;
  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
}

/* 标题层级样式 */
.ai-title {
  font-weight: 600;
  color: #1a365d;
  margin: 16px 0 12px 0;
  padding-bottom: 8px;
  border-bottom: 2px solid #e2e8f0;
}

.ai-title-h1 {
  font-size: 24px;
  color: #2d3748;
  border-bottom-color: #4299e1;
}

.ai-title-h2 {
  font-size: 20px;
  color: #2d3748;
  border-bottom-color: #63b3ed;
}

.ai-title-h3 {
  font-size: 18px;
  color: #4a5568;
  border-bottom-color: #90cdf4;
}

.ai-section-title {
  font-size: 16px;
  font-weight: 600;
  color: #2b6cb0;
  margin: 14px 0 10px 0;
  padding: 8px 12px;
  background: linear-gradient(135deg, #ebf8ff 0%, #bee3f8 100%);
  border-left: 4px solid #4299e1;
  border-radius: 4px;
}

/* 列表样式 */
.ai-list-item {
  font-size: 14px;
  line-height: 1.6;
  color: #4a5568;
  margin: 6px 0;
  padding-left: 4px;
}

.ai-numbered-item {
  color: #2d3748;
  font-weight: 500;
}

.ai-bullet-item {
  padding-left: 16px;
  position: relative;
}

.ai-bullet-item::before {
  content: '▸';
  position: absolute;
  left: 0;
  color: #4299e1;
  font-weight: bold;
}

/* 段落样式 */
.ai-paragraph {
  font-size: 14px;
  line-height: 1.7;
  color: #4a5568;
  margin: 8px 0;
  text-align: left;
}

.ai-paragraph-break {
  height: 12px;
}

/* 特殊符号美化 */
.symbol-dots {
  color: #a0a0a0;
  font-weight: bold;
  letter-spacing: 2px;
}

.symbol-arrow {
  color: #4299e1;
  font-weight: bold;
  margin: 0 4px;
}

.symbol-separator {
  color: #e2a308;
  font-size: 16px;
  display: block;
  text-align: center;
  margin: 16px 0;
}

.symbol-divider {
  color: #cbd5e0;
  display: block;
  text-align: center;
  margin: 12px 0;
  letter-spacing: 4px;
}

/* 新的代码块样式 */
.code-block-wrapper {
  margin: 16px 0;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  overflow: hidden;
  background: #ffffff;
}

.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background: #f6f8fa;
  border-bottom: 1px solid #d0d7de;
}

.code-icon {
  font-size: 16px;
  margin-right: 6px;
}

.code-lang {
  font-size: 12px;
  font-weight: 600;
  color: #656d76;
}

.code-copy-btn {
  padding: 4px 8px;
  font-size: 12px;
  background: #f6f8fa;
  color: #24292f;
  border: 1px solid #d0d7de;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.code-copy-btn:hover {
  background: #f3f4f6;
}

.code-block-content {
  background: #ffffff;
}

.code-block-content pre {
  margin: 0;
  padding: 16px;
  background: transparent;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 12px;
  line-height: 1.45;
  overflow: auto;
  color: #24292f;
  white-space: pre;
}

.code-block-content code {
  background: none;
  color: inherit;
  padding: 0;
  font-size: inherit;
}

/* 消息文本样式 */
.message-title {
  font-size: 16px;
  font-weight: 600;
  color: #24292f;
  margin: 12px 0 8px 0;
  line-height: 1.25;
}

.message-para {
  font-size: 14px;
  line-height: 1.5;
  color: #656d76;
  margin: 8px 0;
}

.message-list {
  font-size: 14px;
  line-height: 1.5;
  color: #656d76;
  margin: 4px 0;
  padding-left: 16px;
}

/* AI消息内容容器 */
.ai-message-content {
  white-space: normal;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
  color: #374151;
}

/* 消息内容通用样式 */
.ai-message-content > * {
  margin: 0;
}

.ai-message-content > *:not(:last-child) {
  margin-bottom: 12px;
}

.ai-message-content p {
  margin: 0 0 12px 0;
  line-height: 1.7;
}

.ai-message-content ul,
.ai-message-content ol {
  margin: 12px 0;
  padding-left: 20px;
}

.ai-message-content li {
  margin: 4px 0;
  line-height: 1.6;
}

.ai-message-content h1,
.ai-message-content h2,
.ai-message-content h3,
.ai-message-content h4,
.ai-message-content h5,
.ai-message-content h6 {
  margin: 16px 0 8px 0;
  color: #1f2937;
  line-height: 1.3;
}

.ai-message-content h1 { font-size: 24px; font-weight: 700; }
.ai-message-content h2 { font-size: 20px; font-weight: 600; }
.ai-message-content h3 { font-size: 18px; font-weight: 600; }
.ai-message-content h4 { font-size: 16px; font-weight: 600; }
.ai-message-content h5 { font-size: 14px; font-weight: 600; }
.ai-message-content h6 { font-size: 13px; font-weight: 600; }

/* 文件头部样式 - 基础样式 */
.file-header {
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: 12px;
  padding: 16px 20px;
  margin: 20px 0 16px 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.file-header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: currentColor;
  opacity: 0.3;
}

.file-header:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  transform: translateY(-1px);
}

.file-icon {
  font-size: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 10px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.file-name {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 16px;
  font-weight: 600;
  color: #1e293b;
  flex: 1;
  word-break: break-all;
}

.file-badge {
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

/* 文件主题样式 */
.file-theme-script {
  background: linear-gradient(135deg, #fff7ed 0%, #fed7aa 20%, #fbbf24 100%);
  border: 1px solid #f59e0b;
  color: #92400e;
}

.file-theme-script .file-badge-script {
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  color: white;
}

.file-theme-vue {
  background: linear-gradient(135deg, #ecfdf5 0%, #a7f3d0 20%, #34d399 100%);
  border: 1px solid #10b981;
  color: #065f46;
}

.file-theme-vue .file-badge-vue {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  color: white;
}

.file-theme-style {
  background: linear-gradient(135deg, #fdf2f8 0%, #f3e8ff 20%, #c084fc 100%);
  border: 1px solid #a855f7;
  color: #7c2d12;
}

.file-theme-style .file-badge-style {
  background: linear-gradient(135deg, #a855f7 0%, #9333ea 100%);
  color: white;
}

.file-theme-markup {
  background: linear-gradient(135deg, #eff6ff 0%, #bfdbfe 20%, #60a5fa 100%);
  border: 1px solid #3b82f6;
  color: #1e40af;
}

.file-theme-markup .file-badge-markup {
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  color: white;
}

.file-theme-config {
  background: linear-gradient(135deg, #f0fdf4 0%, #bbf7d0 20%, #4ade80 100%);
  border: 1px solid #22c55e;
  color: #166534;
}

.file-theme-config .file-badge-config {
  background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
  color: white;
}

.file-theme-media {
  background: linear-gradient(135deg, #fef3c7 0%, #fde68a 20%, #f59e0b 100%);
  border: 1px solid #d97706;
  color: #92400e;
}

.file-theme-media .file-badge-media {
  background: linear-gradient(135deg, #d97706 0%, #b45309 100%);
  color: white;
}

.file-theme-special {
  background: linear-gradient(135deg, #f3e8ff 0%, #ddd6fe 20%, #8b5cf6 100%);
  border: 1px solid #7c3aed;
  color: #5b21b6;
}

.file-theme-special .file-badge-special {
  background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
  color: white;
}

.file-theme-default {
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 20%, #cbd5e1 100%);
  border: 1px solid #94a3b8;
  color: #475569;
}

.file-theme-default .file-badge-default {
  background: linear-gradient(135deg, #64748b 0%, #475569 100%);
  color: white;
}

/* Markdown样式 */
.markdown-heading {
  font-weight: 600;
  line-height: 1.25;
  margin: 24px 0 16px 0;
  padding-bottom: 8px;
  border-bottom: 1px solid #e1e5e9;
  color: #1f2328;
}

.markdown-h1 {
  font-size: 28px;
  border-bottom: 2px solid #fd7e14;
  color: #1f2328;
}

.markdown-h2 {
  font-size: 22px;
  border-bottom: 1px solid #e1e5e9;
  color: #1f2328;
}

.markdown-h3 {
  font-size: 18px;
  border-bottom: none;
  color: #1f2328;
}

.markdown-h4 {
  font-size: 16px;
  color: #1f2328;
}

.markdown-h5 {
  font-size: 14px;
  color: #1f2328;
}

.markdown-h6 {
  font-size: 13px;
  color: #656d76;
}

.markdown-paragraph {
  margin: 0 0 16px 0;
  font-size: 14px;
  line-height: 1.7;
  color: #1f2328;
}

.markdown-list-item {
  margin: 4px 0;
  padding-left: 8px;
  font-size: 14px;
  line-height: 1.7;
  color: #1f2328;
}

/* Markdown代码块样式 */
.markdown-code-block {
  margin: 20px 0;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  overflow: hidden;
  background: #f9fafb;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  transition: all 0.2s ease;
}

.markdown-code-block:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  border-color: #d1d5db;
}

.markdown-code-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  border-bottom: 1px solid #e5e7eb;
}

.markdown-code-info {
  display: flex;
  align-items: center;
  gap: 8px;
}

.markdown-code-icon {
  font-size: 16px;
}

.markdown-code-lang {
  font-size: 13px;
  font-weight: 600;
  color: #374151;
  background: rgba(59, 130, 246, 0.1);
  padding: 2px 8px;
  border-radius: 4px;
  border: 1px solid rgba(59, 130, 246, 0.2);
}

.markdown-copy-btn {
  padding: 6px 12px;
  font-size: 12px;
  background: #ffffff;
  color: #374151;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  font-weight: 500;
}

.markdown-copy-btn:hover {
  background: #f3f4f6;
  border-color: #9ca3af;
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.markdown-code-content {
  background: #ffffff;
  position: relative;
}

.markdown-code-content pre {
  margin: 0;
  padding: 20px;
  background: transparent;
  font-family: 'JetBrains Mono', 'Fira Code', ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 13px;
  line-height: 1.6;
  overflow: auto;
  color: #1f2937;
}

.markdown-code-content code {
  background: none;
  color: inherit;
  padding: 0;
  font-size: inherit;
}










/* Loading样式 */
.loading-message {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}

.loading-content {
  text-align: center;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 16px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.debug-content {
  background: #fff3cd;
  border: 1px solid #ffeaa7;
  color: #856404;
  padding: 8px;
  border-radius: 4px;
  font-family: monospace;
}

.error-content {
  background: #f8d7da;
  border: 1px solid #f5c6cb;
  color: #721c24;
  padding: 8px;
  border-radius: 4px;
  font-family: monospace;
}

/* 原始内容显示（降级使用） */
.raw-content {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: #24292f;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* 基础文本样式优化 */
.message-text > div,
.streaming-content > div {
  line-height: 1.6;
  font-size: 14px;
  color: #333;
}

.streaming-content > div {
  display: inline;
}

/* 标题区域样式 */
.title-content {
  display: flex;
  align-items: center;
  gap: 12px;
}

.app-title {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  color: #1a1a1a;
}

.type-tag {
  font-size: 12px;
  font-weight: 500;
  border-radius: 6px;
  padding: 2px 8px;
  margin: 0;
}

/* 可视化编辑相关样式 */
.selected-element-info {
  margin-bottom: 16px;
}

.element-details {
  font-size: 12px;
  line-height: 1.5;
}

.element-details div {
  margin-bottom: 4px;
}

/* 预览操作区域样式优化 */
.preview-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.preview-actions .edit-button {
  border-radius: 6px;
  transition: all 0.3s ease;
  font-weight: 500;
}

.preview-actions .edit-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.2);
}

.preview-actions .edit-button[type="primary"] {
  background: linear-gradient(135deg, #1890ff 0%, #40a9ff 100%);
  border: none;
  color: white;
}

.preview-actions .edit-button[type="primary"]:hover {
  background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
  transform: translateY(-1px) scale(1.02);
}

/* 编辑模式时的预览区域样式 */
.preview-content {
  position: relative;
  height: 100%;
}

.preview-iframe {
  width: 100%;
  height: 100%;
  transition: all 0.3s ease;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
}

.preview-content.edit-mode .preview-iframe {
  border: 2px solid #1890ff;
  box-shadow: 
    0 0 0 4px rgba(24, 144, 255, 0.1),
    0 4px 12px rgba(24, 144, 255, 0.15);
}

/* 编辑模式浮动角标 */
.edit-mode-badge {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 1000;
  background: rgba(24, 144, 255, 0.95);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-radius: 8px;
  box-shadow: 
    0 4px 12px rgba(24, 144, 255, 0.3),
    0 2px 4px rgba(0, 0, 0, 0.1);
  animation: bounceIn 0.5s ease-out;
  cursor: default;
  user-select: none;
  transition: all 0.3s ease;
  overflow: hidden;
}

.edit-mode-badge:hover {
  transform: translateY(-2px);
  box-shadow: 
    0 6px 20px rgba(24, 144, 255, 0.4),
    0 3px 6px rgba(0, 0, 0, 0.15);
}

.badge-content {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  color: white;
  font-size: 12px;
  font-weight: 600;
}

.badge-icon {
  font-size: 14px;
  color: white;
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.7;
  }
}

.badge-text {
  white-space: nowrap;
}

.badge-tip {
  background: rgba(255, 255, 255, 0.15);
  padding: 4px 12px;
  font-size: 10px;
  color: rgba(255, 255, 255, 0.9);
  text-align: center;
  border-radius: 0 0 8px 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  max-height: 0;
  opacity: 0;
  transition: all 0.3s ease;
}

.edit-mode-badge:hover .badge-tip {
  max-height: 30px;
  opacity: 1;
}

/* 编辑模式角标动画 */
@keyframes bounceIn {
  0% {
    transform: scale(0.3) translateY(-20px);
    opacity: 0;
  }
  50% {
    transform: scale(1.05) translateY(0);
    opacity: 0.8;
  }
  70% {
    transform: scale(0.95);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
  }

/* 聊天区域整体美化 */
.chat-panel {
  background: rgba(255, 255, 255, 0.98);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: 16px;
  border: 1px solid rgba(24, 144, 255, 0.1);
  box-shadow: 
    0 8px 32px rgba(24, 144, 255, 0.08),
    0 4px 16px rgba(0, 0, 0, 0.04);
  overflow: hidden;
}

.messages-container {
  flex: 0.9;
  padding: 16px;
  overflow-y: auto;
  scroll-behavior: smooth;
  position: relative;
}

/* 回到底部按钮 */
.scroll-to-bottom-button {
  position: fixed;
  bottom: 150px;
  right: 60px;
  z-index: 1000;
  animation: fadeInUp 0.3s ease;
}

.scroll-to-bottom-button .ant-btn {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  background: #1890ff;
  border-color: #1890ff;
}

.scroll-to-bottom-button .ant-btn:hover {
  background: #40a9ff;
  border-color: #40a9ff;
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.message-item {
  margin-bottom: 12px;
}

.user-message {
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 8px;
}

.ai-message {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 8px;
}

.message-content {
  max-width: 70%;
  padding: 12px 16px;
  border-radius: 12px;
  line-height: 1.5;
  word-wrap: break-word;
}

.user-message .message-content {
  background: #1890ff;
  color: white;
}

.ai-message .message-content {
  background: #f5f5f5;
  color: #1a1a1a;
  padding: 8px 12px;
}

.message-avatar {
  flex-shrink: 0;
}

.loading-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #666;
}

/* 加载更多按钮美化 */
.load-more-container {
  text-align: center;
  padding: 8px 0;
  margin-bottom: 16px;
}

.load-more-btn {
  background: rgba(24, 144, 255, 0.05) !important;
  border: 1px solid rgba(24, 144, 255, 0.2) !important;
  border-radius: 20px !important;
  color: #1890ff !important;
  font-size: 12px;
  padding: 6px 16px;
  height: auto !important;
  transition: all 0.3s ease !important;
}

.load-more-btn:hover {
  background: rgba(24, 144, 255, 0.1) !important;
  border-color: #1890ff !important;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(24, 144, 255, 0.15) !important;
}

/* 加载状态样式 */
.loading-message {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
}

.loading-content {
  text-align: center;
  color: #666;
}

.loading-spinner {
  width: 24px;
  height: 24px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 12px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}



/* 消息头像 */
.message-avatar {
  flex-shrink: 0;
}

/* AI头像logo样式 */
.ai-avatar {
  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%) !important;
  border: 2px solid rgba(24, 144, 255, 0.2) !important;
  box-shadow: 
    0 4px 12px rgba(24, 144, 255, 0.15),
    0 2px 4px rgba(0, 0, 0, 0.05),
    inset 0 1px 0 rgba(255, 255, 255, 0.4) !important;
  transition: all 0.3s ease !important;
  position: relative;
}

.ai-avatar:hover {
  transform: scale(1.08) !important;
  box-shadow: 
    0 6px 20px rgba(24, 144, 255, 0.25),
    0 3px 6px rgba(0, 0, 0, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.5) !important;
}
</style>
.ai-avatar {
  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%) !important;
  border: 2px solid rgba(24, 144, 255, 0.2) !important;
  box-shadow: 
    0 4px 12px rgba(24, 144, 255, 0.15),
    0 2px 4px rgba(0, 0, 0, 0.05),
    inset 0 1px 0 rgba(255, 255, 255, 0.4) !important;
  transition: all 0.3s ease !important;
  position: relative;
}

.ai-avatar::before {
  content: '';
  position: absolute;
  top: -3px;
  left: -3px;
  right: -3px;
  bottom: -3px;
  background: linear-gradient(45deg, #40a9ff, #1890ff, #40a9ff);
  border-radius: 50%;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.ai-avatar:hover::before {
  opacity: 0.3;
  animation: rotate 3s linear infinite;
}

.ai-avatar:hover {
  transform: scale(1.08) !important;
  border-color: rgba(24, 144, 255, 0.4) !important;
  box-shadow: 
    0 6px 20px rgba(24, 144, 255, 0.25),
    0 3px 6px rgba(0, 0, 0, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.5) !important;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* 消息头像通用样式 */

/* 模仿图片的现代化输入区域 */
.input-container {
  padding: 24px 32px 32px 32px !important;
  background: #ffffff !important;
  border-top: 1px solid #e8e8e8 !important;
  position: relative !important;
  min-height: 120px !important;
}

.input-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, 0.1) 50%, transparent 100%);
}

/* 模仿图片的输入框容器 */
.input-wrapper {
  position: relative !important;
  display: block !important;
  width: 100% !important;
  overflow: visible !important;
  background: #ffffff !important;
  border-radius: 12px !important;
  border: 1px solid #e0e0e0 !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06) !important;
  transition: all 0.2s ease !important;
  min-height: 140px !important;
}

.input-wrapper:hover {
  border-color: #c0c0c0 !important;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08) !important;
}

.input-wrapper:focus-within {
  border-color: #1890ff !important;
  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1), 0 4px 12px rgba(0, 0, 0, 0.08) !important;
}

.ant-tooltip .input-wrapper {
  position: relative !important;
  display: block !important;
  width: 100% !important;
  overflow: visible !important;
  background: #ffffff;
  border-radius: 12px;
  border: 1px solid #e0e0e0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  transition: all 0.2s ease;
  min-height: 140px;
}

/* 确保tooltip不影响定位和样式 */
.ant-tooltip {
  display: block !important;
  width: 100% !important;
}

/* 模仿图片的文本输入框 */
.input-wrapper .ant-input,
.input-wrapper textarea.ant-input {
  width: 100% !important;
  border: none !important;
  border-radius: 12px !important;
  padding: 20px 60px 60px 20px !important;
  font-size: 14px !important;
  line-height: 1.5 !important;
  resize: none !important;
  transition: all 0.2s ease !important;
  background: transparent !important;
  min-height: 120px !important;
  max-height: 300px !important;
  color: #333333 !important;
  font-weight: 400 !important;
  box-shadow: none !important;
  outline: none !important;
}

.input-wrapper .ant-input:hover,
.input-wrapper textarea.ant-input:hover {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
}

.input-wrapper .ant-input:focus,
.input-wrapper textarea.ant-input:focus {
  background: transparent !important;
  outline: none !important;
  box-shadow: none !important;
  border: none !important;
}

.input-wrapper .ant-input::placeholder,
.input-wrapper textarea.ant-input::placeholder {
  color: #999999 !important;
  font-weight: 400 !important;
  font-size: 14px !important;
}

/* 模仿图片的发送按钮区域 */
.input-actions {
  position: absolute !important;
  bottom: 16px !important;
  right: 16px !important;
  z-index: 1000 !important;
  pointer-events: auto !important;
}

.input-wrapper .input-actions {
  position: absolute !important;
  bottom: 16px !important;
  right: 16px !important;
  z-index: 1000 !important;
}

.ant-tooltip .input-wrapper .input-actions {
  position: absolute !important;
  bottom: 16px !important;
  right: 16px !important;
  z-index: 1000 !important;
}

/* 模仿图片的发送按钮样式 */
.input-actions .ant-btn {
  position: relative !important;
  width: 36px !important;
  height: 36px !important;
  border-radius: 50% !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  background: #1890ff !important;
  border: none !important;
  color: white !important;
  font-size: 16px !important;
  cursor: pointer !important;
  transition: all 0.2s ease !important;
  box-shadow: 0 2px 6px rgba(24, 144, 255, 0.3) !important;
  min-width: 36px !important;
  max-width: 36px !important;
  padding: 0 !important;
  margin: 0 !important;
}


.input-actions .ant-btn:hover {
  background: #40a9ff !important;
  transform: scale(1.05) !important;
  box-shadow: 0 4px 8px rgba(24, 144, 255, 0.4) !important;
}

.input-actions .ant-btn:active {
  transform: scale(0.95) !important;
  box-shadow: 0 2px 4px rgba(24, 144, 255, 0.3) !important;
}

.input-actions .ant-btn:disabled {
  background: #d9d9d9 !important;
  color: #999999 !important;
  cursor: not-allowed !important;
  transform: none !important;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
}


/* 输入框动画效果 */
@keyframes inputFocus {
  0% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-1px) scale(1.002);
  }
  100% {
    transform: translateY(-2px) scale(1.002);
  }
}

@keyframes buttonPulse {
  0% {
    box-shadow: 0 4px 12px rgba(24, 144, 255, 0.25), 0 2px 6px rgba(24, 144, 255, 0.15);
  }
  50% {
    box-shadow: 0 6px 16px rgba(24, 144, 255, 0.3), 0 3px 8px rgba(24, 144, 255, 0.2);
  }
  100% {
    box-shadow: 0 4px 12px rgba(24, 144, 255, 0.25), 0 2px 6px rgba(24, 144, 255, 0.15);
  }
}

/* 加载状态特殊样式 */
.input-actions .ant-btn.ant-btn-loading {
  background: #52c41a !important;
}

.input-actions .ant-btn.ant-btn-loading:hover {
  background: #73d13d !important;
}

/* 响应式优化 */
@media (max-width: 768px) {
  .input-container {
    padding: 20px 24px 24px 24px;
    min-height: 100px;
  }
  
  .input-wrapper {
    min-height: 120px;
  }
  
  .input-wrapper .ant-input {
    padding: 16px 50px 50px 16px;
    min-height: 100px;
    font-size: 14px;
  }
  
  .input-actions {
    bottom: 12px !important;
    right: 12px !important;
  }
  
  .input-actions .ant-btn {
    width: 32px !important;
    height: 32px !important;
    min-width: 32px !important;
    max-width: 32px !important;
    font-size: 14px !important;
  }
}


/* 欢迎消息简化 */
.welcome-message {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  background: #f5f5f5;
  border-radius: 8px;
  border: 1px dashed #ccc;
}

.welcome-content {
  text-align: center;
  max-width: 300px;
  padding: 20px;
}

.welcome-icon {
  font-size: 36px;
  color: #1890ff;
  margin-bottom: 12px;
}

.welcome-content h3 {
  color: #333;
  font-size: 16px;
  font-weight: 500;
  margin-bottom: 8px;
}

.welcome-content p {
  color: #666;
  font-size: 13px;
  line-height: 1.4;
  margin-bottom: 4px;
}

/* 流式输出简化 */
.streaming-content {
  /* 移除复杂动画 */
}

/* Vue项目生成的特殊加载样式 */
.vue-project-loading {
  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
  border: 2px solid #0ea5e9;
  border-radius: 16px;
  padding: 24px;
  margin: 16px 0;
  display: flex;
  align-items: center;
  gap: 20px;
  box-shadow: 0 4px 20px rgba(14, 165, 233, 0.1);
  animation: vue-loading-pulse 3s ease-in-out infinite;
}

@keyframes vue-loading-pulse {
  0%, 100% {
    box-shadow: 0 4px 20px rgba(14, 165, 233, 0.1);
    border-color: #0ea5e9;
  }
  50% {
    box-shadow: 0 8px 30px rgba(14, 165, 233, 0.2);
    border-color: #0284c7;
  }
}

.vue-loading-animation {
  flex-shrink: 0;
}

.vue-loading-tips {
  flex: 1;
}

.vue-loading-tips h4 {
  color: #0c4a6e;
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 8px 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.vue-loading-tips p {
  color: #075985;
  font-size: 14px;
  margin: 0 0 16px 0;
  line-height: 1.5;
}

.loading-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px;
}

.loading-steps .step {
  background: rgba(255, 255, 255, 0.7);
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 12px;
  color: #0c4a6e;
  font-weight: 500;
  border: 1px solid rgba(14, 165, 233, 0.2);
  animation: step-appear 0.5s ease-out;
}

.loading-steps .step:nth-child(1) { animation-delay: 0.2s; }
.loading-steps .step:nth-child(2) { animation-delay: 0.4s; }
.loading-steps .step:nth-child(3) { animation-delay: 0.6s; }
.loading-steps .step:nth-child(4) { animation-delay: 0.8s; }

@keyframes step-appear {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 响应式适配 */
@media (max-width: 768px) {
  .vue-project-loading {
    flex-direction: column;
    text-align: center;
    gap: 16px;
  }
  
  .loading-steps {
    grid-template-columns: 1fr;
  }
}

/* AI头像logo样式 */
.ai-avatar {
  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%) !important;
  border: 2px solid rgba(24, 144, 255, 0.2) !important;
  box-shadow: 
    0 4px 12px rgba(24, 144, 255, 0.15),
    0 2px 4px rgba(0, 0, 0, 0.05),
    inset 0 1px 0 rgba(255, 255, 255, 0.4) !important;
  transition: all 0.3s ease !important;
  position: relative;
}

.ai-avatar:hover {
  transform: scale(1.08) !important;
  box-shadow: 
    0 6px 20px rgba(24, 144, 255, 0.25),
    0 3px 6px rgba(0, 0, 0, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.5) !important;
}
